crt0dat.c
来自「C语言库函数的原型,有用的拿去」· C语言 代码 · 共 989 行 · 第 1/2 页
C
989 行
/***
*crt0dat.c - 32-bit C run-time initialization/termination routines
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* This module contains the routines _cinit, exit, and _exit
* for C run-time startup and termination. _cinit and exit
* are called from the _astart code in crt0.asm.
* This module also defines several data variables used by the
* runtime.
*
* [NOTE: Lock segment definitions are at end of module.]
*
*******************************************************************************/
#include <cruntime.h>
#include <msdos.h>
#include <rtcapi.h>
#include <dos.h>
#include <oscalls.h>
#include <mtdll.h>
#include <internal.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <dbgint.h>
#include <sect_attribs.h>
#include <mbctype.h>
#include <mbdata.h>
/* define umask */
int _umaskval = 0;
/* argument vector and environment */
_CRTIMP int __argc = 0;
_CRTIMP char **__argv = NULL;
_CRTIMP wchar_t **__wargv = NULL;
_CRTIMP char **_environ = NULL;
_CRTIMP char **__initenv = NULL;
_CRTIMP wchar_t **_wenviron = NULL;
_CRTIMP wchar_t **__winitenv = NULL;
_CRTIMP char *_pgmptr = NULL; /* ptr to program name */
_CRTIMP wchar_t *_wpgmptr = NULL; /* ptr to wide program name */
/* callable exit flag */
char _exitflag = 0;
/*
* flag indicating if C runtime termination has been done. set if exit,
* _exit, _cexit or _c_exit has been called. checked when _CRTDLL_INIT
* is called with DLL_PROCESS_DETACH.
*/
int _C_Termination_Done = FALSE;
int _C_Exit_Done = FALSE;
#ifndef CRTDLL
/*
* Flag checked by getenv() and _putenv() to determine if the environment has
* been initialized.
*/
int __env_initialized;
#endif /* CRTDLL */
#ifdef _MBCS
/*
* Flag to ensure multibyte ctype table is only initialized once
*/
int __mbctype_initialized;
#endif /* _MBCS */
/*
* NOTE: THE USE OF THE POINTERS DECLARED BELOW DEPENDS ON THE PROPERTIES
* OF C COMMUNAL VARIABLES. SPECIFICALLY, THEY ARE NON-NULL IFF THERE EXISTS
* A DEFINITION ELSEWHERE INITIALIZING THEM TO NON-NULL VALUES.
*/
/*
* pointers to initialization functions
*/
#ifndef CRTDLL
const _PVFI _FPinit; /* floating point init. */
#endif /* CRTDLL */
/*
* pointers to initialization sections
*/
extern _CRTALLOC(".CRT$XIA") _PIFV __xi_a[];
extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; /* C initializers */
extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; /* C++ initializers */
extern _CRTALLOC(".CRT$XPA") _PVFV __xp_a[];
extern _CRTALLOC(".CRT$XPZ") _PVFV __xp_z[]; /* C pre-terminators */
extern _CRTALLOC(".CRT$XTA") _PVFV __xt_a[];
extern _CRTALLOC(".CRT$XTZ") _PVFV __xt_z[]; /* C terminators */
/*
* pointers to the start and finish of the _onexit/atexit table
* NOTE - the pointers are stored encoded.
*/
_PVFV *__onexitbegin;
_PVFV *__onexitend;
/*
* Pointer to callback function to initialize any dynamically initialized
* __declspec(thread) variables. This relies on a subtle aspect of C.
* The pointer is defined here uninitialized. It is defined initialized in
* tlsdyn.c. If user code uses dynamically initialized __declspec(thread)
* variables, then compiler-injected dependencies cause tlsdyn.obj to be
* linked. In that case, the non-zero definition of __dyn_tls_init_callback
* in tlsdyn.obj will take precedence, and the startup code will execute the
* callback. This use of multiple definitions is only legal in C, not C++.
*/
#ifndef CRTDLL
const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
#endif /* CRTDLL */
/*
* static (internal) functions that walk a table of function pointers,
* calling each entry between the two pointers, skipping NULL entries
*
* _initterm needs to be exported for CRT DLL so that C++ initializers in the
* client EXE / DLLs can be initialized.
*
* _initterm_e calls function pointers that return a nonzero error code to
* indicate an initialization failed fatally.
*/
#ifdef CRTDLL
void __cdecl _initterm(_PVFV *, _PVFV *);
#else /* CRTDLL */
static void __cdecl _initterm(_PVFV *, _PVFV *);
#endif /* CRTDLL */
int __cdecl _initterm_e(_PIFV *, _PIFV *);
#ifdef CRTDLL
/*
Copied from dllstuff\crtexe.c.
*/
/***
*check_managed_app() - Check for a managed executable
*
*Purpose:
* Determine if the EXE the startup code is linked into is a managed app
* by looking for the COM Runtime Descriptor in the Image Data Directory
* of the PE or PE+ header.
*
*Entry:
* None
*
*Exit:
* 1 if managed app, 0 if not.
*
*Exceptions:
*
*******************************************************************************/
static int __cdecl check_managed_app (
void
)
{
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_NT_HEADERS pPEHeader;
pDOSHeader = (PIMAGE_DOS_HEADER) GetModuleHandleW(NULL);
if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
pPEHeader = (PIMAGE_NT_HEADERS) ((BYTE *) pDOSHeader + pDOSHeader->e_lfanew);
if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
switch (pPEHeader->OptionalHeader.Magic) {
PIMAGE_OPTIONAL_HEADER32 pOptHeader32;
#ifdef _WIN64
PIMAGE_OPTIONAL_HEADER64 pOptHeader64;
#endif /* _WIN64 */
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
/* PE header */
pOptHeader32 = (PIMAGE_OPTIONAL_HEADER32) &pPEHeader->OptionalHeader;
if (pOptHeader32->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
{
return 0;
}
return pOptHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != 0;
#ifdef _WIN64
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
/* PE+ header */
pOptHeader64 = (PIMAGE_OPTIONAL_HEADER64) &pPEHeader->OptionalHeader;
if (pOptHeader64->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
{
return 0;
}
return pOptHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != 0;
#endif /* _WIN64 */
}
/* Not PE or PE+, so not managed */
return 0;
}
#endif /* CRTDLL */
/***
*_cinit - C initialization
*
*Purpose:
* This routine performs the shared DOS and Windows initialization.
* The following order of initialization must be preserved -
*
* 1. Check for devices for file handles 0 - 2
* 2. Integer divide interrupt vector setup
* 3. General C initializer routines
*
*Entry:
* No parameters: Called from __crtstart and assumes data
* set up correctly there.
*
*Exit:
* Initializes C runtime data.
* Returns 0 if all .CRT$XI internal initializations succeeded, else
* the _RT_* fatal error code encountered.
*
*Exceptions:
*
*******************************************************************************/
#ifndef CRTDLL
extern void __cdecl _initp_misc_cfltcvt_tab();
#endif /* CRTDLL */
int __cdecl _cinit (
int initFloatingPrecision
)
{
int initret;
/*
* initialize floating point package, if present
*/
#ifdef CRTDLL
_fpmath(initFloatingPrecision);
#else /* CRTDLL */
if (_FPinit != NULL &&
_IsNonwritableInCurrentImage((PBYTE)&_FPinit))
{
(*_FPinit)(initFloatingPrecision);
}
_initp_misc_cfltcvt_tab();
#endif /* CRTDLL */
/*
* do initializations
*/
initret = _initterm_e( __xi_a, __xi_z );
if ( initret != 0 )
return initret;
#ifdef _RTC
atexit(_RTC_Terminate);
#endif /* _RTC */
/*
* do C++ initializations
*/
_initterm( __xc_a, __xc_z );
#ifndef CRTDLL
/*
* If we have any dynamically initialized __declspec(thread)
* variables, then invoke their initialization for the thread on
* which the DLL is being loaded, by calling __dyn_tls_init through
* a callback defined in tlsdyn.obj. We can't rely on the OS
* calling __dyn_tls_init with DLL_PROCESS_ATTACH because, on
* Win2K3 and before, that call happens before the CRT is
* initialized.
*/
if (__dyn_tls_init_callback != NULL &&
_IsNonwritableInCurrentImage((PBYTE)&__dyn_tls_init_callback))
{
__dyn_tls_init_callback(NULL, DLL_THREAD_ATTACH, NULL);
}
#endif /* CRTDLL */
return 0;
}
/***
*exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
*
*Purpose:
*
* Entry points:
*
* exit(code): Performs all the C termination functions
* and terminates the process with the return code
* supplied by the user.
*
* _exit(code): Performs a quick exit routine that does not
* do certain 'high-level' exit processing. The _exit
* routine terminates the process with the return code
* supplied by the user.
*
* _cexit(): Performs the same C lib termination processing
* as exit(code) but returns control to the caller
* when done (i.e., does NOT terminate the process).
*
* _c_exit(): Performs the same C lib termination processing
* as _exit(code) but returns control to the caller
* when done (i.e., does NOT terminate the process).
*
* Termination actions:
*
* exit(), _cexit():
*
* 1. call user's terminator routines
* 2. call C runtime preterminators
*
* _exit(), _c_exit():
*
* 3. call C runtime terminators
* 4. return to DOS or caller
*
* Notes:
*
* The termination sequence is complicated due to the multiple entry
* points sharing the common code body while having different entry/exit
* sequences.
*
* Multi-thread notes:
*
* 1. exit() should NEVER be called when mthread locks are held.
* The exit() routine can make calls that try to get mthread locks.
*
* 2. _exit()/_c_exit() can be called from anywhere, with or without locks held.
* Thus, _exit() can NEVER try to get locks (otherwise, deadlock
* may occur). _exit() should always 'work' (i.e., the process
* should always terminate successfully).
*
* 3. Only one thread is allowed into the exit code (see _lockexit()
* and _unlockexit() routines).
*
*Entry:
* exit(), _exit()
* int status - exit status (0-255)
*
* _cexit(), _c_exit()
* <no input>
*
*Exit:
* exit(), _exit()
* <EXIT to DOS>
*
* _cexit(), _c_exit()
* Return to caller
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/
/* worker routine prototype */
static void __cdecl doexit (int code, int quick, int retcaller);
void __cdecl exit (
int code
)
{
doexit(code, 0, 0); /* full term, kill process */
}
void __cdecl _exit (
int code
)
{
doexit(code, 1, 0); /* quick term, kill process */
}
void __cdecl _cexit (
void
)
{
doexit(0, 0, 1); /* full term, return to caller */
}
void __cdecl _c_exit (
void
)
{
doexit(0, 1, 1); /* quick term, return to caller */
}
/***
*_amsg_exit(rterrnum) - Fast exit fatal errors
*
*Purpose:
* Exit the program with error code of 255 and appropriate error
* message.
*
*Entry:
* int rterrnum - error message number (amsg_exit only).
*
*Exit:
* Calls _exit()
*
*Exceptions:
*
*******************************************************************************/
void __cdecl _amsg_exit (
int rterrnum
)
{
_FF_MSGBANNER(); /* write run-time error banner */
_NMSG_WRITE(rterrnum); /* write message */
_exit(255);
}
#ifdef _DEBUG
/***
* __freeCrtMemory()
*
* Purpose:
* To free as much as CRT memory as possible. This helps in keeping CRT leaks as
* minimum.
*
*******************************************************************************/
void __cdecl __freeCrtMemory()
{
void **pptr;
for (pptr = _wenviron; pptr != NULL && *pptr != NULL; ++pptr) {
_free_crt(*pptr);
}
_free_crt(_wenviron);
_wenviron = NULL;
pptr = _environ;
for (; pptr != NULL && *pptr != NULL; ++pptr) {
_free_crt(*pptr);
}
_free_crt(_environ);
_environ = NULL;
_free_crt(__wargv);
_free_crt(__argv);
_free_crt(DecodePointer(__onexitbegin));
__wargv = NULL;
__argv = NULL;
__onexitbegin = (_PVFV *)_encoded_null();
if (InterlockedDecrement(&(__ptmbcinfo->refcount)) == 0 && __ptmbcinfo != &__initialmbcinfo)
{
_free_crt(__ptmbcinfo);
__ptmbcinfo = &__initialmbcinfo;
}
InterlockedIncrement(&(__ptmbcinfo->refcount));
}
#endif /* _DEBUG */
static void __cdecl doexit (
int code,
int quick,
int retcaller
)
{
#ifdef _DEBUG
static int fExit = 0;
#endif /* _DEBUG */
#ifdef CRTDLL
if (!retcaller && check_managed_app())
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?