我正在寻找更技术性的解释,然后操作系统调用该函数。
任何人都可以帮助我或将我指向一个网站或书籍吗?
.exe 文件(或其他平台上的等效文件)包含一个“入口点”地址。大致上,操作系统将 .EXE 文件的相关部分加载到 ram 中,然后跳转到入口点。
正如其他人所说,这个入口点不会是“main”,而是运行时库的一部分——它会做一些事情,比如初始化静态对象、设置 argc/argv 参数、设置 stdin/stdout/stderr等。完成所有这些后,它将调用您的 main() 函数。当 main 退出时,运行时会经历一个类似的过程,将返回代码传回环境,调用静态析构函数,调用 _atexit 例程等。
如果你有 MS 工具(也许不是免费的),那么你就有了所有运行时源代码,查看它的一种简单方法是在 main() 方法的右大括号上放置一个断点,然后单步备份进入运行时。
main()
是 C 库的一部分,不是系统函数。我不知道 OS X 或 Linux,但 Windows 通常以WinMainCRTStartup()
. 此符号初始化您的进程,提取命令行参数和环境 ( argc, argv, end
) 并调用main()
。它还负责调用应该在之后运行的任何代码main()
,例如atexit()
.
通过查看您的 Visual Studio 文件,您应该能够找到 的默认实现WinMainCRTStartup
以了解它的作用。
您还可以定义自己的函数以在启动时调用,这是通过更改链接器选项中的“入口点”来完成的。这通常是一个不带参数并返回 void 的函数。
就 Windows 而言,入口点功能是:
void __cdecl mainCRTStartup( void ) {}
void __stdcall WinMainCRTStartup( void ) {}
BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {}
使用这些而不是普通的 main/WinMain/DllMain 的唯一原因是如果您想使用自己的运行时库(如果您想要更小的文件大小或自定义功能)
有关自定义运行时实现和其他获取更小的 PE 文件的技巧,请参阅:
Expert C++/CLI(查看第 279 页)有非常具体的关于本机、混合和纯 CLR 程序集的不同引导方案的详细信息。
它取决于操作系统。在 OS X 中,mach 标头中有一个帧,其中包含 EIP(指令指针)寄存器的起始地址。
一旦二进制文件被加载,操作系统就会从这个地址开始执行:
cristi:test diciu$ otool -l ./a.out | grep -A 10 LC_UNIXTHREAD cmd LC_UNIXTHREAD cmdsize 80 风味 i386_THREAD_STATE 计数 i386_THREAD_STATE_COUNT [..] ss 0x00000000 eflags 0x00000000 eip 0x00001f8c cs 0x00000000 [..]
地址是二进制文件中“start”函数的地址:
cristi:test diciu$ nm ./a.out 0000200c D_NXArgc 00002008 D_NXArgv 00002000 D ___程序名称 00001fe0 t __dyld_func_lookup 00001000 A __mh_execute_header [..] 00001f8c T 开始
在 Mac OS X 中,首先调用的是“start”函数,甚至在“main”函数之前:
(gdb) b 开始 0x1f90 处的断点 1 (gdb) b 主要 0x1ff4 处的断点 2 (gdb) r 启动程序:/Users/diciu/Programming/test/a.out 共享库 ++ 的读取符号。完毕 断点 1, 0x00001f90 in start()