收录查询

crt0.c代码内容解释和编译器构造

下面用红色字体,做部分解释:

  1/***
  2*crt0.c - C runtime initialization routine
  3*
  4*       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5*
  6*Purpose:
  7*       This the actual startup routine for apps.  It calls the user's main
  8*       routine [w]main() or [w]WinMain after performing C Run-Time Library
  9*       initialization.
 10*
 11*       (With ifdef's, this source file also provides the source code for
 12*       wcrt0.c, the startup routine for console apps with wide characters,
 13*       wincrt0.c, the startup routine for Windows apps, and wwincrt0.c,
 14*       the startup routine for Windows apps with wide characters.)
 15*
 16*******************************************************************************/

 17
 18#ifdef _WIN32
 19
 20#ifndef CRTDLL
 21
 22#include <cruntime.h>
 23#include <dos.h>
 24#include <internal.h>
 25#include <stdlib.h>
 26#include <string.h>
 27#include <rterr.h>
 28#include <windows.h>
 29#include <awint.h>
 30#include <tchar.h>
 31#include <dbgint.h>
 32
 33/*
 34 * wWinMain is not yet defined in winbase.h. When it is, this should be
 35 * removed.
 36 */

 37
 38int
 39WINAPI
 40wWinMain(
 41    HINSTANCE hInstance,
 42    HINSTANCE hPrevInstance,
 43    LPWSTR lpCmdLine,
 44    int nShowCmd
 45    );
 46
 47#ifdef WPRFLAG
 48_TUCHAR * __cdecl _wwincmdln(void);
 49#else  /* WPRFLAG */
 50_TUCHAR * __cdecl _wincmdln(void);
 51#endif  /* WPRFLAG */
 52
 53/*
 54 * command line, environment, and a few other globals
 55 */

 56
 57#ifdef WPRFLAG
 58wchar_t *_wcmdln;           /* points to wide command line */
 59#else  /* WPRFLAG */
 60char *_acmdln;              /* points to command line */
 61#endif  /* WPRFLAG */
 62
 63char *_aenvptr = NULL;      /* points to environment block */
 64wchar_t *_wenvptr = NULL;   /* points to wide environment block */
 65
 66
 67void (__cdecl * _aexit_rtn)(int= _exit;   /* RT message return procedure */
 68
 69static void __cdecl fast_error_exit(int);   /* Error exit via ExitProcess */
 70
 71/*
 72 * _error_mode and _apptype, together, determine how error messages are
 73 * written out.
 74 */

 75int __error_mode = _OUT_TO_DEFAULT;
 76#ifdef _WINMAIN_
 77int __app_type = _GUI_APP;
 78#else  /* _WINMAIN_ */
 79int __app_type = _CONSOLE_APP;
 80#endif  /* _WINMAIN_ */
 81
 82
 83/***
 84*BaseProcessStartup(PVOID Peb)
 85*
 86*Purpose:
 87*       This routine does the C runtime initialization, calls main(), and
 88*       then exits.  It never returns.
 89*
 90*Entry:
 91*       PVOID Peb - pointer to Win32 Process Environment Block (not used)
 92*
 93*Exit:
 94*       This function never returns.
 95*
 96*******************************************************************************/

 97
 98#ifdef _WINMAIN_
 99
100#ifdef WPRFLAG
101void wWinMainCRTStartup(
102#else  /* WPRFLAG */
103void WinMainCRTStartup(
104#endif  /* WPRFLAG */
105
106#else  /* _WINMAIN_ */
107
108#ifdef WPRFLAG
109void wmainCRTStartup(
110#else  /* WPRFLAG */
111void mainCRTStartup(
112#endif  /* WPRFLAG */
113
114#endif  /* _WINMAIN_ */
115        void
116        )
117
118{
119        int mainret;
120
121#ifdef _WINMAIN_
122        _TUCHAR *lpszCommandLine;
123        STARTUPINFO StartupInfo;
124#endif  /* _WINMAIN_ */
125
126        /*
127         * Get the full Win32 version
128         */

129        _osver = GetVersion();
130
131        _winminor = (_osver >> 8& 0x00FF ;
132        _winmajor = _osver & 0x00FF ;
133        _winver = (_winmajor << 8+ _winminor;
134        _osver = (_osver >> 16& 0x00FFFF ;
135
136#ifdef _MT
137        if ( !_heap_init(1) )               /* initialize heap */
138#else  /* _MT */
139        if ( !_heap_init(0) )               /* initialize heap */
140#endif  /* _MT */
141            fast_error_exit(_RT_HEAPINIT);  /* write message and die */
142
143#ifdef _MT
144        if!_mtinit() )                    /* initialize multi-thread */
145            fast_error_exit(_RT_THREAD);    /* write message and die */
146#endif  /* _MT */
147
148        /*
149         * Guard the remainder of the initialization code and the call
150         * to user's main, or WinMain, function in a __try/__except
151         * statement.
152         */

153
154        __try {
155
156            _ioinit();                      /* initialize lowio */
157
158#ifdef WPRFLAG
159            /* get wide cmd line info */
160            _wcmdln = (wchar_t *)__crtGetCommandLineW();
161
162            /* get wide environ info */
163            _wenvptr = (wchar_t *)__crtGetEnvironmentStringsW();
164
165            _wsetargv();
166            _wsetenvp();
167#else  /* WPRFLAG */
168            /* get cmd line info */
169            _acmdln = (char *)GetCommandLineA();
170
171            /* get environ info */
172            _aenvptr = (char *)__crtGetEnvironmentStringsA();
173
174            _setargv();
175            _setenvp();
176#endif  /* WPRFLAG */
177
178            _cinit();                       /* do C data initialize */
179
180#ifdef _WINMAIN_
181
182            StartupInfo.dwFlags = 0;
183            GetStartupInfo( &StartupInfo );
184
185#ifdef WPRFLAG
186            lpszCommandLine = _wwincmdln();
187            mainret = wWinMain(
188#else  /* WPRFLAG */
189            lpszCommandLine = _wincmdln();
190            mainret = WinMain(
191#endif  /* WPRFLAG */
192                               GetModuleHandleA(NULL),
193                               NULL,
194                               lpszCommandLine,
195                               StartupInfo.dwFlags & STARTF_USESHOWWINDOW
196                                    ? StartupInfo.wShowWindow
197                                    : SW_SHOWDEFAULT
198                             );
199#else  /* _WINMAIN_ */
200
201#ifdef WPRFLAG
202            __winitenv = _wenviron;
203            mainret = wmain(__argc, __wargv, _wenviron);
204#else  /* WPRFLAG */
205            __initenv = _environ;
206            mainret = main(__argc, __argv, _environ);
207#endif  /* WPRFLAG */
208
209#endif  /* _WINMAIN_ */
210            exit(mainret);
211        }

212        __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
213        {
214            /*
215             * Should never reach here
216             */

217            _exit( GetExceptionCode() );
218
219        }
 /* end of try - except */
220
221}

222
223
224
225/***
226*_amsg_exit(rterrnum) - Fast exit fatal errors
227*
228*Purpose:
229*       Exit the program with error code of 255 and appropriate error
230*       message.
231*
232*Entry:
233*       int rterrnum - error message number (amsg_exit only).
234*
235*Exit:
236*       Calls exit() (for integer divide-by-0) or _exit() indirectly
237*       through _aexit_rtn [amsg_exit].
238*       For multi-thread: calls _exit() function
239*
240*Exceptions:
241*
242*******************************************************************************/

243
244void __cdecl _amsg_exit (
245        int rterrnum
246        )
247{
248#ifdef _WINMAIN_
249        if ( __error_mode == _OUT_TO_STDERR )
250#else  /* _WINMAIN_ */
251        if ( __error_mode != _OUT_TO_MSGBOX )
252#endif  /* _WINMAIN_ */
253            _FF_MSGBANNER();    /* write run-time error banner */
254
255        _NMSG_WRITE(rterrnum);  /* write message */
256        _aexit_rtn(255);        /* normally _exit(255) */
257}

258
259/***
260*fast_error_exit(rterrnum) - Faster exit fatal errors
261*
262*Purpose:
263*       Exit the process with error code of 255 and appropriate error
264*       message.
265*
266*Entry:
267*       int rterrnum - error message number (amsg_exit only).
268*
269*Exit:
270*       Calls ExitProcess.
271*
272*Exceptions:
273*
274*******************************************************************************/

275
276static void __cdecl fast_error_exit (
277        int rterrnum
278        )
279{
280#ifdef _WINMAIN_
281        if ( __error_mode == _OUT_TO_STDERR )
282#else  /* _WINMAIN_ */
283        if ( __error_mode != _OUT_TO_MSGBOX )
284#endif  /* _WINMAIN_ */
285            _FF_MSGBANNER();    /* write run-time error banner */
286
287        _NMSG_WRITE(rterrnum);  /* write message */
288        ExitProcess(255);       /* normally _exit(255) */
289}

290
291#ifndef WPRFLAG
292
293
294#endif  /* WPRFLAG */
295
296#endif  /* CRTDLL */
297
298#else  /* _WIN32 */
299
300#include <cruntime.h>
301#include <internal.h>
302#include <stdlib.h>
303#include <msdos.h>
304#include <string.h>
305#include <setjmp.h>
306#include <dbgint.h>
307#include <macos\types.h>
308#include <macos\segload.h>
309#include <macos\gestalte.h>
310#include <macos\osutils.h>
311#include <macos\traps.h>
312#include <mpw.h>
313
314static void __cdecl Inherit(void);  /* local function */
315
316int __cdecl main(intchar **char **);             /*generated by compiler*/
317
318unsigned long _GetShellStack(void);
319
320static char * __cdecl _p2cstr_internal ( unsigned char * str );
321
322extern MPWBLOCK * _pMPWBlock;
323extern int __argc;
324extern char **__argv;
325
326/***
327*__crt0()
328*
329*Purpose:
330*       This routine does the C runtime initialization, calls main(), and
331*       then exits.  It never returns.
332*
333*Entry:
334*
335*Exit:
336*       This function never returns.
337*
338*******************************************************************************/

339
340void __cdecl __crt0 (
341        )
342{
343        int mainret;
344        char szPgmName[32];
345        char *pArg;
346        char *argv[2];
347
348#ifndef _M_MPPC
349        void *pv;
350
351        /* This is the magic stuff that MPW tools do to get info from MPW*/
352
353        pv = (void *)*(int *)0x316;
354        if (pv != NULL && !((int)pv & 1&& *(int *)pv == 'MPGM'{
355            pv = (void *)*++(int *)pv;
356            if (pv != NULL && *(short *)pv == 'SH'{
357                _pMPWBlock = (MPWBLOCK *)pv;
358            }

359        }

360
361#endif  /* _M_MPPC */
362
363        _environ = NULL;
364        if (_pMPWBlock == NULL) {
365            __argc = 1;
366            memcpy(szPgmName, (char *)0x910sizeof(szPgmName));
367            pArg = _p2cstr_internal(szPgmName);
368            argv[0= pArg;
369            argv[1= NULL;
370            __argv = argv;
371
372#ifndef _M_MPPC
373            _shellStack = 0;                        /* force ExitToShell */
374#endif  /* _M_MPPC */
375        }

376#ifndef _M_MPPC
377        else {
378            _shellStack = _GetShellStack();        //return current a6, or first a6
379            _shellStack += 4;                      //a6 + 4 is the stack pointer we want
380            __argc = _pMPWBlock->argc;
381            __argv = _pMPWBlock->argv;
382
383            Inherit();       /* Inherit file handles - env is set up by _envinit if needed */
384        }

385#endif  /* _M_MPPC */
386
387        /*
388         * call run time initializer
389         */

390        __cinit();
391
392        mainret = main(__argc, __argv, _environ);
393        exit(mainret);
394}

395
396
397#ifndef _M_MPPC
398/***
399*Inherit() - obtain and process info on inherited file handles.
400*
401*Purpose:
402*
403*       Locates and interprets MPW std files.  For files we just save the
404*       file handles.   For the console we save the device table address so
405*       we can do console I/O.  In the latter case, FDEV is set in the _osfile
406*       array.
407*
408*Entry:
409*       Address of MPW param table
410*
411*Exit:
412*       No return value.
413*
414*Exceptions:
415*
416*******************************************************************************/

417
418static void __cdecl Inherit (
419        void
420        )
421{
422        MPWFILE *pFile;
423        int i;
424        pFile = _pMPWBlock->pFile;
425        if (pFile == NULL) {
426            return;
427        }

428        for (i = 0; i < 3; i++{
429            switch ((pFile->pDevice)->name) {
430                case 'ECON':
431                    _osfile[i] |= FDEV | FOPEN;
432                    _osfhnd[i] = (int)pFile;
433                    break;
434
435                case 'FSYS':
436                    _osfile[i] |= FOPEN;
437                    _osfhnd[i] = (*(pFile->ppFInfo))->ioRefNum;
438                    break;
439            }

440            pFile++;
441        }

442}

443
444#endif  /* _M_MPPC */
445
446
447
448static char * __cdecl _p2cstr_internal (
449        unsigned char * str
450        )
451{
452        unsigned char *pchSrc;
453        unsigned char *pchDst;
454        int  cch;
455
456        if ( str && *str ) {
457            pchDst = str;
458            pchSrc = str + 1;
459
460            for ( cch=*pchDst; cch; --cch ) {
461                *pchDst++ = *pchSrc++;
462            }

463
464            *pchDst = '\0';
465        }

466
467        return( str );
468}

469
470#endif  /* _WIN32 */
471

1. 应用程序类型--------只有2类:要么是CUI, 要么是GUI
2. 程序真正的启动代码(入口点函数)-----------各种**CRTStartUp
3. 环境变量+命令行信息的相关变量和函数都在此文件中有定义或声明
4. 调用运行时初始化+main()函数的最后返回和报错信息在下面的代码定义了
 1*******************************************************************************/
 2
 3void __cdecl __crt0 (
 4        )
 5{
 6        int mainret;
 7        char szPgmName[32];
 8        char *pArg;
 9        char *argv[2];
10
11#ifndef _M_MPPC
12        void *pv;
13
14        /* This is the magic stuff that MPW tools do to get info from MPW*/
15
16        pv = (void *)*(int *)0x316;
17        if (pv != NULL && !((int)pv & 1&& *(int *)pv == 'MPGM'{
18            pv = (void *)*++(int *)pv;
19            if (pv != NULL && *(short *)pv == 'SH'{
20                _pMPWBlock = (MPWBLOCK *)pv;
21            }

22        }

23
24#endif  /* _M_MPPC */
25
26        _environ = NULL;
27        if (_pMPWBlock == NULL) {
28            __argc = 1;
29            memcpy(szPgmName, (char *)0x910sizeof(szPgmName));
30            pArg = _p2cstr_internal(szPgmName);
31            argv[0= pArg;
32            argv[1= NULL;
33            __argv = argv;
34
35#ifndef _M_MPPC
36            _shellStack = 0;                        /* force ExitToShell */
37#endif  /* _M_MPPC */
38        }

39#ifndef _M_MPPC
40        else {
41            _shellStack = _GetShellStack();        //return current a6, or first a6
42            _shellStack += 4;                      //a6 + 4 is the stack pointer we want
43            __argc = _pMPWBlock->argc;
44            __argv = _pMPWBlock->argv;
45
46            Inherit();       /* Inherit file handles - env is set up by _envinit if needed */
47        }

48#endif  /* _M_MPPC */
49
50        /*
51         * call run time initializer
52         */

53        __cinit();
54
55        mainret = main(__argc, __argv, _environ);
56        exit(mainret);
57}

58
59

5. 获取进程信息+响应中断的代码如下:
 1/***
 2*Inherit() - obtain and process info on inherited file handles.
 3*
 4*Purpose:
 5*
 6*       Locates and interprets MPW std files.  For files we just save the
 7*       file handles.   For the console we save the device table address so
 8*       we can do console I/O.  In the latter case, FDEV is set in the _osfile
 9*       array.
10*
11*Entry:
12*       Address of MPW param table
13*
14*Exit:
15*       No return value.
16*
17*Exceptions:
18*
19*******************************************************************************/

20
21static void __cdecl Inherit (
22        void
23        )
24{
25        MPWFILE *pFile;
26        int i;
27        pFile = _pMPWBlock->pFile;
28        if (pFile == NULL) {
29            return;
30        }

31        for (i = 0; i < 3; i++{
32            switch ((pFile->pDevice)->name) {
33                case 'ECON':
34                    _osfile[i] |= FDEV | FOPEN;
35                    _osfhnd[i] = (int)pFile;
36                    break;
37
38                case 'FSYS':
39                    _osfile[i] |= FOPEN;
40                    _osfhnd[i] = (*(pFile->ppFInfo))->ioRefNum;
41                    break;
42            }

43            pFile++;
44        }

45}

46
47#endif  /* _M_MPPC */
48
49
50
51static char * __cdecl _p2cstr_internal (
52        unsigned char * str
53        )
54{
55        unsigned char *pchSrc;
56        unsigned char *pchDst;
57        int  cch;
58
59        if ( str && *str ) {
60            pchDst = str;
61            pchSrc = str + 1;
62
63            for ( cch=*pchDst; cch; --cch ) {
64                *pchDst++ = *pchSrc++;
65            }

66
67            *pchDst = '\0';
68        }

69
70        return( str );
71}

72
73#endif  /* _WIN32 */

6. 如果是GUI程序,则要创建“内核对象”,请参考下面的MSDN中的STARTUPINFO结构体的说明
http://www.cnblogs.com/shanzy/articles/513455.html

7. 上面的crt0.c文件中涉及到MS针对不同的CPU厂商都能够跑MS的VC编译器的CPU假设,如下面MSDN文章所说------------当然,你也可以在代码中手写下面这些MS预定义宏,或者写MAKEFILE

Predefined Macros

The compiler recognizes six predefined ANSI C macros (see Table 1.1), and the Microsoft C++ implementation provides several more (see Table 1.2). These macros take no arguments and cannot be redefined. Their value (except for __LINE__ and __FILE__) must be constant throughout compilation. Some of the predefined macros listed below are defined with multiple values. Their values can be set by selecting the corresponding menu option in the Visual C++ development environment, or by using a command-line switch. See the tables below for more information.

Table 1.1   ANSI Predefined Macros

Macro Description
__DATE__ The compilation date of the current source file. The date is a string literal of the form Mmm dd yyyy. The month name Mmm is the same as for dates generated by the library function asctime declared in TIME.H.
__FILE__ The name of the current source file. __FILE__ expands to a string surrounded by double quotation marks.
__LINE__ The line number in the current source file. The line number is a decimal integer constant. It can be altered with a #line directive.
__STDC__ Indicates full conformance with the ANSI C standard. Defined as the integer constant 1 only if the /Za compiler option is given and you are not compiling C++ code; otherwise is undefined.
__TIME__ The most recent compilation time of the current source file. The time is a string literal of the form hh:mm:ss.
__TIMESTAMP__ The date and time of the last modification of the current source file, expressed as a string literal in the form Ddd Mmm Date hh:mm:ss yyyy, where Ddd is the abbreviated day of the week and Date is an integer from 1 to 31.

 

Table 1.2   Microsoft-Specific Predefined Macros

Macro Description
_CHAR_UNSIGNED Default char type is unsigned. Defined when /J is specified.
__cplusplus Defined for C++ programs only.
_CPPRTTI Defined for code compiled with /GR (Enable Run-Time Type Information).
_CPPUNWIND Defined for code compiled with /GX (Enable Exception Handling).
_DLL Defined when /MD or /MDd (Multithread DLL) is specified.
_M_ALPHA Defined for DEC ALPHA platforms. It is defined as 1 by the ALPHA compiler, and it is not defined if another compiler is used.
_M_IX86 Defined for x86 processors. See Table 1.3 for more details.
_M_MPPC Defined for Power Macintosh platforms. Default is 601 (/QP601). See Table 1.4 for more details.
_M_MRX000 Defined for MIPS platforms. Default is 4000 (/QMR4000). See Table 1.5 for more details.
_M_PPC Defined for PowerPC platforms. Default is 604 (/QP604). See Table 1.6 for more details.
_MFC_VER Defines the MFC version. Defined as 0x0421 for Microsoft Foundation Class Library 4.21. Always defined.
_MSC_EXTENSIONS This macro is defined when compiling with the /Ze compiler option (the default).  Its value, when defined, is 1.
_MSC_VER Defines the compiler version. Defined as 1200 for Microsoft Visual C++ 6.0. Always defined.
_MT Defined when /MD or /MDd (Multithreaded DLL) or /MT or /MTd (Multithreaded) is specified.
_WIN32 Defined for applications for Win32®. Always defined.

As shown in following tables, the compiler generates a value for the preprocessor identifiers that reflect the processor option specified.

Table 1.3   Values for _M_IX86

Option in Developer Studio Command-Line Option Resulting Value
Blend /GB _M_IX86 = 500 (Default. Future compilers will emit a different value to reflect the dominant processor.)
Pentium /G5 _M_IX86 = 500
Pentium Pro /G6 _M_IX86 = 600
80386 /G3 _M_IX86 = 300
80486 /G4 _M_IX86 = 400

 

Table 1.4   Values for _M_MPPC

Option in development environment Command-Line Option Resulting Value
PowerPC 601 /QP601 _M_MPPC = 601 (Default)
PowerPC 603 /QP603 _M_MPPC = 603
PowerPC 604 /QP604 _M_MPPC = 604
PowerPC 620 /QP620 _M_MPPC = 620

 

Table 1.5   Values for _M_MRX000

Option in Developer Studio Command-Line Option Resulting Value
R4000 /QMR4000 _M_MRX000 = 4000 (Default)
R4100 /QMR4100 _M_MRX000 = 4100
R4200 /QMR4200 _M_MRX000 = 4200
R4400 /QMR4400 _M_MRX000 = 4400
R4600 /QMR4600 _M_MRX000 = 4600
R10000 /QMR10000 _M_MRX000 = 10000

 

Table 1.6   Values for _M_PPC

Option in Developer Studio Command-Line Option Resulting Value
PowerPC 601 /QP601 _M_PPC = 601
PowerPC 603 /QP603 _M_PPC = 603
PowerPC 604 /QP604 _M_PPC = 604 (Default)
PowerPC 620 /QP620 _M_PPC = 620

8. 任何C/C++编译器的构造,都是依托于ANSI C/ANSI C++标准的,但是,由于某些历史问题当ANSI标准影响了厂商的标准,或者厂商认为某些东西更利于开发的时候,厂商会在ANSI标准提供的编译器的基础上对CRT运行时库进行扩充,扩充的结果就是上面的情况

9. 厂商扩充了ANSI标准,就需要写出一个自己的编译器(MS 的VC编译器就是cl.exe),写这个cl.exe的过程要根据厂商扩充之后的各种标准表格,在写这个cl.exe的时候做出很多的选择分支(当然,MS这里用它认为重要的一些“自定义宏”来写它的cl.exe)
posted @ 2006-09-24 17:45  ->  阅读(2263)  评论(0编辑  收藏  举报