mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
594 lines
17 KiB
594 lines
17 KiB
/***
|
|
*crt0.c - C runtime initialization routine
|
|
*
|
|
* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* This the main startup routine. It is called upon program
|
|
* startup by a very small assembler stub.
|
|
*
|
|
*Revision History:
|
|
* 06-27-89 PHG Module created, based on asm version
|
|
* 11-02-89 JCR Added DOS32QUERYSYSINFO to get osversion
|
|
* 04-09-90 GJF Added #include <cruntime.h>. Put in explicit calling
|
|
* types (_CALLTYPE1 or _CALLTYPE4) for __crt0(),
|
|
* inherit(), __amsg_exit() and _cintDIV(). Also, fixed
|
|
* the copyright and cleaned up the formatting a bit.
|
|
* 04-10-90 GJF Fixed compiler warnings (-W3).
|
|
* 08-08-90 GJF Added exception handling stuff (needed to support
|
|
* runtime errors and signal()).
|
|
* 08-31-90 GJF Removed 32 from API names.
|
|
* 10-08-90 GJF New-style function declarators.
|
|
* 12-05-90 GJF Fixed off-by-one error in inherit().
|
|
* 12-06-90 GJF Win32 version of inherit().
|
|
* 12-06-90 SRW Added _osfile back for win32. Changed _osfinfo from
|
|
* an array of structures to an array of 32-bit handles
|
|
* (_osfhnd)
|
|
* 01-21-91 GJF ANSI naming.
|
|
* 01-25-91 SRW Changed Win32 Process Startup [_WIN32_]
|
|
* 02-01-91 SRW Removed usage of PPEB type [_WIN32_]
|
|
* 02-05-91 SRW Changed to pass _osfile and _osfhnd arrays as binary
|
|
* data to child process. [_WIN32_]
|
|
* 04-02-91 GJF Need to get version number sooner so it can be used in
|
|
* _heap_init. Prefixed an '_' onto BaseProcessStartup.
|
|
* Version info now stored in _os[version|major|minor] and
|
|
* _base[version|major|minor] (_WIN32_).
|
|
* 04-10-91 PNT Added _MAC_ conditional
|
|
* 04-26-91 SRW Removed level 3 warnings
|
|
* 05-14-91 GJF Turn on exception handling for Dosx32.
|
|
* 05-22-91 GJF Fixed careless errors.
|
|
* 07-12-91 GJF Fixed one more careless error.
|
|
* 08-13-91 GJF Removed definitions of _confh and _coninpfh.
|
|
* 09-13-91 GJF Incorporated Stevewo's startup variations.
|
|
* 11-07-91 GJF Revised try-except, fixed outdated comments on file
|
|
* handle inheritance [_WIN32_].
|
|
* 12-02-91 SRW Fixed WinMain startup code to skip over first token
|
|
* plus delimiters for the lpszCommandLine parameter.
|
|
* 01-17-92 GJF Merge of NT and CRT version. Restored Stevewo's scheme
|
|
* for unhandled exceptions.
|
|
* 02-13-92 GJF For Win32, moved file inheritance stuff to ioinit.c.
|
|
* Call to inherit() is replace by call to _ioinit().
|
|
* 04-16-92 DJM POSIX support
|
|
* 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
|
|
* 08-26-92 GJF Deleted version number(s) fetch from POSIX startup (it
|
|
* involved a Win32 API call).
|
|
* 09-30-92 SRW Call _heap_init before _mtinit
|
|
* 04-26-93 GJF Made lpszCommandLine (unsigned char *) to deal with
|
|
* chars > 127 in the command line.
|
|
* 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV,
|
|
* _RT_INVALDISP and _RT_NONCONT.
|
|
* 05-11-93 SKS Remove obsolete variable _atopsp
|
|
* Change _mtinit to return failure
|
|
* 05-14-93 GJF Added support for quoted program names.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <cruntime.h>
|
|
#include <dos.h>
|
|
#include <internal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef _POSIX_
|
|
#include <rterr.h>
|
|
#else
|
|
#include <posix/sys/types.h>
|
|
#include <posix/unistd.h>
|
|
#include <posix/signal.h>
|
|
#endif
|
|
#include <oscalls.h>
|
|
|
|
#ifdef _CRUISER_
|
|
/*
|
|
* C file info string
|
|
*/
|
|
char _acfinfo[] = "_C_FILE_INFO=";
|
|
#endif /* _CRUISER_ */
|
|
|
|
/*
|
|
* command line, environment, and a few other globals
|
|
*/
|
|
char *_acmdln; /* points to command line */
|
|
char *_aenvptr; /* points to environment block */
|
|
|
|
#ifdef _POSIX_
|
|
char *_cmdlin;
|
|
#endif
|
|
|
|
void (_CRTAPI1 * _aexit_rtn)(int) = _exit; /* RT message return procedure */
|
|
|
|
#ifdef _CRUISER_
|
|
static void _CRTAPI3 inherit(void); /* local function */
|
|
#endif /* _CRUISER_ */
|
|
|
|
#ifndef _MAC_
|
|
|
|
#ifdef _POSIX_
|
|
|
|
/***
|
|
*mainCRTStartup(PVOID Peb)
|
|
*
|
|
*Purpose:
|
|
* This routine does the C runtime initialization, calls main(), and
|
|
* then exits. It never returns.
|
|
*
|
|
*Entry:
|
|
* PVOID Peb - pointer to Win32 Process Environment Block (not used)
|
|
*
|
|
*Exit:
|
|
* This function never returns.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void
|
|
mainCRTStartup(
|
|
void
|
|
)
|
|
{
|
|
int mainret;
|
|
char **ppch;
|
|
|
|
extern char **environ;
|
|
extern char * __PdxGetCmdLine(void); /* a hacked API in the Posix SS */
|
|
extern main(int,char**);
|
|
|
|
_cmdlin = __PdxGetCmdLine();
|
|
ppch = (char **)_cmdlin;
|
|
__argv = ppch;
|
|
|
|
// normalize argv pointers
|
|
|
|
__argc = 0;
|
|
while (NULL != *ppch) {
|
|
*ppch += (int)_cmdlin;
|
|
++__argc;
|
|
++ppch;
|
|
}
|
|
// normalize environ pointers
|
|
|
|
++ppch;
|
|
environ = ppch;
|
|
|
|
while (NULL != *ppch) {
|
|
*ppch = *ppch + (int)_cmdlin;
|
|
++ppch;
|
|
}
|
|
|
|
/*
|
|
* If POSIX runtime needs to fetch and store POSIX verion info,
|
|
* it should be done here.
|
|
*
|
|
* Get_and_save_version_info;
|
|
*/
|
|
|
|
_heap_init(); /* initialize heap */
|
|
_cinit(); /* do C data initialize */
|
|
|
|
try {
|
|
mainret = main(__argc, __argv);
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
switch (GetExceptionCode()) {
|
|
case STATUS_ACCESS_VIOLATION:
|
|
kill(getpid(), SIGSEGV);
|
|
break;
|
|
case STATUS_ILLEGAL_INSTRUCTION:
|
|
case STATUS_PRIVILEGED_INSTRUCTION:
|
|
kill(getpid(), SIGILL);
|
|
break;
|
|
case STATUS_FLOAT_DENORMAL_OPERAND:
|
|
case STATUS_FLOAT_DIVIDE_BY_ZERO:
|
|
case STATUS_FLOAT_INEXACT_RESULT:
|
|
case STATUS_FLOAT_OVERFLOW:
|
|
case STATUS_FLOAT_STACK_CHECK:
|
|
case STATUS_FLOAT_UNDERFLOW:
|
|
kill(getpid(), SIGFPE);
|
|
break;
|
|
default:
|
|
kill(getpid(), SIGKILL);
|
|
}
|
|
|
|
mainret = -1;
|
|
}
|
|
exit(mainret);
|
|
}
|
|
#else /* ndef _POSIX_ */
|
|
|
|
#ifdef _CRUISER_
|
|
|
|
/***
|
|
*__crt0(cmdline, envptr)
|
|
*
|
|
*Purpose:
|
|
* This routine does the C runtime initialization, calls main(), and
|
|
* then exits. It never returns.
|
|
*
|
|
*Entry:
|
|
* char *cmdline - pointer to OS/2 command line
|
|
* char *envptr - pointer to OS/2 environment block
|
|
*
|
|
*Exit:
|
|
* This function never returns.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void _CRTAPI1 __crt0 (
|
|
char *cmdline,
|
|
char *envptr
|
|
)
|
|
{
|
|
int mainret;
|
|
|
|
/* initialize pointers to command line and environment */
|
|
_acmdln = cmdline;
|
|
_aenvptr = envptr;
|
|
|
|
/* Get the OS/2 version */
|
|
|
|
/* make sure our assumptions are correct */
|
|
|
|
#if (_QSV_VERSION_MAJOR+1 != _QSV_VERSION_MINOR)
|
|
#error Invalid DosQuerySysInfo parameters
|
|
#endif
|
|
|
|
DOSQUERYSYSINFO(_QSV_VERSION_MAJOR, _QSV_VERSION_MINOR,
|
|
(unsigned char *)&_osmajor, (2*sizeof(int)) );
|
|
|
|
#else /* ndef _CRUISER_ */
|
|
|
|
#ifdef _WIN32_
|
|
|
|
/***
|
|
*BaseProcessStartup(PVOID Peb)
|
|
*
|
|
*Purpose:
|
|
* This routine does the C runtime initialization, calls main(), and
|
|
* then exits. It never returns.
|
|
*
|
|
*Entry:
|
|
* PVOID Peb - pointer to Win32 Process Environment Block (not used)
|
|
*
|
|
*Exit:
|
|
* This function never returns.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#ifdef _DOSX32_
|
|
|
|
void _BaseProcessStartup (
|
|
|
|
#else
|
|
|
|
#ifdef _WINMAIN_
|
|
void WinMainCRTStartup(
|
|
#else
|
|
void mainCRTStartup(
|
|
#endif
|
|
|
|
#endif
|
|
void
|
|
)
|
|
|
|
{
|
|
int mainret;
|
|
|
|
#ifdef _WINMAIN_
|
|
unsigned char *lpszCommandLine;
|
|
STARTUPINFOA StartupInfo;
|
|
#endif
|
|
_acmdln = (char *)GetCommandLine();
|
|
_aenvptr = (char *)GetEnvironmentStrings();
|
|
|
|
/*
|
|
* Get the full Win32 version
|
|
*/
|
|
_osversion = /* OBSOLETE */
|
|
_osver = GetVersion();
|
|
|
|
_winminor = (_osver >> 8) & 0x00FF ;
|
|
_winmajor = _osver & 0x00FF ;
|
|
_winver = (_winmajor << 8) + _winminor;
|
|
_osver = (_osver >> 16) & 0x00FFFF ;
|
|
|
|
/* --------- The following block is OBSOLETE --------- */
|
|
|
|
/*
|
|
* unpack base version info
|
|
*/
|
|
_baseversion = (_osversion & 0xFFFF0000) >> 16;
|
|
_baseminor = _baseversion & 0x00FF;
|
|
_basemajor = (_baseversion & 0xFF00) >> 8;
|
|
|
|
/*
|
|
* unpack top-level version info (Windows version)
|
|
*/
|
|
_osversion &= 0x0000FFFF;
|
|
_osmajor = _osversion & 0x00FF;
|
|
_osminor = (_osversion & 0xFF00) >> 8;
|
|
|
|
/* --------- The preceding block is OBSOLETE --------- */
|
|
|
|
#else /* ndef _WIN32_ */
|
|
|
|
#error ERROR - ONLY CRUISER OR WIN32 TARGET SUPPORTED!
|
|
|
|
#endif /* _WIN32_ */
|
|
|
|
#endif /* _CRUISER_ */
|
|
|
|
_heap_init(); /* initialize heap */
|
|
#ifdef MTHREAD
|
|
if(!_mtinit()) /* initialize multi-thread */
|
|
_amsg_exit(_RT_THREAD); /* write message and die */
|
|
#endif
|
|
#ifdef _WIN32_
|
|
_ioinit(); /* initialize lowio */
|
|
#else /* ndef _WIN32_ */
|
|
#ifdef _CRUISER_
|
|
inherit(); /* inherit file info */
|
|
#endif /* _CRUISER_ */
|
|
#endif /* _WIN32_ */
|
|
_setargv(); /* get cmd line info */
|
|
_setenvp(); /* get environ info */
|
|
|
|
_cinit(); /* do C data initialize */
|
|
|
|
/* now call the main program, and then exit with the return value
|
|
we get back */
|
|
|
|
/*
|
|
* NOTE: THERE MUST BE NO PROTOTYPE FOR THE main() FUNCTION IF THIS
|
|
* IS BUILT FOR THE 386 WITH _stdcall AS THE DEFAULT CALLING TYPE!
|
|
* OTHERWISE, THE STACK WILL NOT BE PROPERLY RESTORED AFTER THE CALL
|
|
* BELOW. WE MIGHT GET AWAY WITH THIS, SINCE WE EXIT RIGHT AWAY, BUT
|
|
* THERE IS NO POINT IN ASKING FOR TROUBLE.
|
|
*/
|
|
|
|
#ifdef _CRUISER_
|
|
|
|
_try {
|
|
mainret = main(__argc, __argv, _environ);
|
|
}
|
|
_except ( _XcptFilter(_exception_code(), _exception_info()) )
|
|
{
|
|
switch( _exception_code() ) {
|
|
|
|
case _XCPT_UNABLE_TO_GROW_STACK :
|
|
_amsg_exit(_RT_STACK);
|
|
|
|
case _XCPT_INTEGER_DIVIDE_BY_ZERO :
|
|
/*
|
|
* NOTE: THIS IS WHERE cintDIV WENT!
|
|
*
|
|
* exit via high-level exit function
|
|
*/
|
|
_aexit_rtn = exit;
|
|
_amsg_exit(_RT_INTDIV);
|
|
|
|
case _XCPT_INVALID_DISPOSITION :
|
|
/*
|
|
* this exception should never occur. if it
|
|
* does, it would have to be a bug in the
|
|
* runtime support for signal() or SEH.
|
|
*/
|
|
_amsg_exit(_RT_INVALDISP);
|
|
|
|
case _XCPT_NONCONTINUABLE_EXCEPTION :
|
|
/*
|
|
* this exception could possibly occur as the
|
|
* result of a bad user exception filter or
|
|
* an error in _XcptFilter().
|
|
*/
|
|
_amsg_exit(_RT_NONCONT);
|
|
|
|
case _XCPT_SIGABRT :
|
|
/*
|
|
* no message is printed unless abort() was
|
|
* called in which case, abort() prints out
|
|
* the termination message before raising the
|
|
* signal
|
|
*/
|
|
_exit(3);
|
|
|
|
default :
|
|
/*
|
|
* no default action, should never get here
|
|
*/
|
|
;
|
|
} /* end of switch */
|
|
|
|
} /* end of _try - _except */
|
|
|
|
#else /* ndef _CRUISER_ */
|
|
|
|
#ifdef _WIN32_
|
|
|
|
try {
|
|
#ifdef _WINMAIN_
|
|
/*
|
|
* Skip past program name (first token in command line).
|
|
* Check for and handle quoted program name.
|
|
*/
|
|
lpszCommandLine = (unsigned char *)_acmdln;
|
|
|
|
if ( *lpszCommandLine == '\"' ) {
|
|
/*
|
|
* Scan, and skip over, subsequent characters until
|
|
* another double-quote or a null is encountered.
|
|
*/
|
|
while ( *++lpszCommandLine && (*lpszCommandLine
|
|
!= '\"') );
|
|
/*
|
|
* If we stopped on a double-quote (usual case), skip
|
|
* over it.
|
|
*/
|
|
if ( *lpszCommandLine == '\"' )
|
|
lpszCommandLine++;
|
|
}
|
|
else {
|
|
while (*lpszCommandLine > ' ')
|
|
lpszCommandLine++;
|
|
}
|
|
|
|
/*
|
|
* Skip past any white space preceeding the second token.
|
|
*/
|
|
while (*lpszCommandLine && (*lpszCommandLine <= ' ')) {
|
|
lpszCommandLine++;
|
|
}
|
|
|
|
StartupInfo.dwFlags = 0;
|
|
GetStartupInfoA( &StartupInfo );
|
|
|
|
mainret = WinMain( GetModuleHandle(NULL),
|
|
NULL,
|
|
lpszCommandLine,
|
|
StartupInfo.dwFlags & STARTF_USESHOWWINDOW
|
|
? StartupInfo.wShowWindow
|
|
: SW_SHOWDEFAULT
|
|
);
|
|
#else
|
|
mainret = main(__argc, __argv, _environ);
|
|
#endif
|
|
exit(mainret);
|
|
}
|
|
except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
|
|
{
|
|
/*
|
|
* Should never reach here
|
|
*/
|
|
_exit( GetExceptionCode() );
|
|
|
|
} /* end of try - except */
|
|
|
|
#else /* ndef _WIN32_ */
|
|
|
|
#error ERROR - ONLY CRUISER, WIN32, MAC, OR POSIX TARGET SUPPORTED!
|
|
|
|
#endif /* _WIN32_ */
|
|
|
|
#endif /* _CRUISER_ */
|
|
|
|
}
|
|
|
|
#endif /* _POSIX_ */
|
|
|
|
#endif /* ndef _MAC_ */
|
|
|
|
|
|
#ifdef _CRUISER_
|
|
|
|
/***
|
|
*inherit() - obtain and process info on inherited file handles.
|
|
*
|
|
*Purpose:
|
|
*
|
|
* Locates and interprets the C_FILE_INFO environment variable.
|
|
*
|
|
* The value of the variable is written into the "_osfile" array.
|
|
*
|
|
* Format: _C_FILE_INFO=<AA><BB><CC><DD>...
|
|
*
|
|
* This variable is a environment variable where each pair of
|
|
* successive letters from one byte in _osfile. The letters are
|
|
* in the reange "A" through "P" representing the 0 though 15.
|
|
* The first letter of each pair is the more significant 4 bits
|
|
* of the result.
|
|
*
|
|
*Entry:
|
|
* No parameters: reads the environment.
|
|
*
|
|
*Exit:
|
|
* No return value.
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
static void _CRTAPI3 inherit (
|
|
void
|
|
)
|
|
{
|
|
char *p; /* pointer to environment strings */
|
|
unsigned char byte; /* byte we build up */
|
|
int fh; /* handle we're on */
|
|
|
|
p = _aenvptr;
|
|
while (*p != '\0') {
|
|
if (strncmp(p, _acfinfo, CFI_LENGTH + 1) == 0) {
|
|
/* found the _C_FILE_INFO string, now parse it */
|
|
p += CFI_LENGTH + 1; /* point to value */
|
|
fh = 0;
|
|
do
|
|
{
|
|
byte = (*p++ - 'A') << 4;
|
|
byte += *p++ - 'A'; /* read byte */
|
|
_osfile[fh++] = byte;
|
|
}
|
|
while(byte);
|
|
|
|
break;
|
|
}
|
|
else
|
|
p += strlen(p) + 1; /* advance to next string */
|
|
}
|
|
}
|
|
|
|
#endif /* _CRUISER_ */
|
|
|
|
|
|
/***
|
|
*_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() (for integer divide-by-0) or _exit() indirectly
|
|
* through _aexit_rtn [amsg_exit].
|
|
* For multi-thread: calls _exit() function
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void _CRTAPI1 _amsg_exit (
|
|
int rterrnum
|
|
)
|
|
{
|
|
_FF_MSGBANNER(); /* write run-time error banner */
|
|
_NMSG_WRITE(rterrnum); /* write message */
|
|
|
|
_aexit_rtn(255); /* normally _exit(255) */
|
|
}
|
|
|
|
#ifdef _POSIX_
|
|
|
|
/***
|
|
*RaiseException() - stub for posix FP routines
|
|
*
|
|
*Purpose:
|
|
* Stub of a Win32 API that posix can't call
|
|
*
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
VOID
|
|
WINAPI
|
|
RaiseException(
|
|
DWORD dwExceptionCode,
|
|
DWORD dwExceptionFlags,
|
|
DWORD nNumberOfArguments,
|
|
LPDWORD lpArguments
|
|
)
|
|
{
|
|
}
|
|
|
|
#endif /* _POSIX_ */
|