下面用红色字体,做部分解释:
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)