下面用红色字体,做部分解释:
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
38
int
39
WINAPI
40
wWinMain(
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
58
wchar_t
*
_wcmdln;
/**/
/* points to wide command line */
59
#else
/* WPRFLAG */
60
char
*
_acmdln;
/**/
/* points to command line */
61
#endif
/* WPRFLAG */
62
63
char
*
_aenvptr
=
NULL;
/**/
/* points to environment block */
64
wchar_t
*
_wenvptr
=
NULL;
/**/
/* points to wide environment block */
65
66
67
void
(__cdecl
*
_aexit_rtn)(
int
)
=
_exit;
/**/
/* RT message return procedure */
68
69
static
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 */
75
int
__error_mode
=
_OUT_TO_DEFAULT;
76
#ifdef _WINMAIN_
77
int
__app_type
=
_GUI_APP;
78
#else
/* _WINMAIN_ */
79
int
__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
101
void
wWinMainCRTStartup(
102
#else
/* WPRFLAG */
103
void
WinMainCRTStartup(
104
#endif
/* WPRFLAG */
105
106
#else
/* _WINMAIN_ */
107
108
#ifdef WPRFLAG
109
void
wmainCRTStartup(
110
#else
/* WPRFLAG */
111
void
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
244
void
__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
276
static
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
314
static
void
__cdecl Inherit(
void
);
/**/
/* local function */
315
316
int
__cdecl main(
int
,
char
**
,
char
**
);
/**/
/*generated by compiler*/
317
318
unsigned
long
_GetShellStack(
void
);
319
320
static
char
*
__cdecl _p2cstr_internal ( unsigned
char
*
str );
321
322
extern
MPWBLOCK
*
_pMPWBlock;
323
extern
int
__argc;
324
extern
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
340
void
__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 *)0x910, sizeof(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
418
static
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
448
static
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
3
void
__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 *)0x910, sizeof(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
21
static
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
51
static
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)