在C / C ++程序中,系统(windows,linux,mac OS X)如何调用main()函数
我正在寻找一个更技术性的解释然后OS调用该函数。 任何人都可以帮助我或指向我的网站或书籍吗?
.exe文件(或其他平台上的等效文件)包含“入口点”地址。 对于第一个近似值,OS将.EXE文件的相关部分加载到ram中,然后跳转到入口点。
正如其他人所说,这个入口点不是’main’,而是成为运行时库的一部分 – 它将执行诸如初始化静态对象,设置argc / argv参数,设置stdin / stdout / stderr之类的操作。完成所有这些后,它将调用你的main()函数。 当主要退出时,运行时会经历一个将返回代码传递回环境,调用静态析构函数,调用_atexit例程等的类似过程。
如果你有MS工具(可能不是免费赠送的工具),那么你拥有所有的运行时源代码,一个简单的方法就是在你的main()方法的右括号上放一个断点,然后单步备份进入运行时。
main()
是C库的一部分,不是系统函数。 我不知道OS X或Linux,但Windows通常使用WinMainCRTStartup()
启动程序。 此符号初始化您的进程,提取命令行参数和环境( argc, argv, end
)并调用main()
。 它还负责调用应该在main()
之后运行的任何代码,如atexit()
。
通过查看Visual Studio文件,您应该能够找到WinMainCRTStartup
的默认实现,以查看它的作用。
您还可以定义自己的函数以在启动时调用,这可以通过更改链接器选项中的“入口点”来完成。 这通常是一个不带参数并返回void的函数。
就Windows而言,入口点function是:
- 控制台:
void __cdecl mainCRTStartup( void ) {}
- GUI:
void __stdcall WinMainCRTStartup( void ) {}
- DLL:
BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {}
在普通的main / WinMain / DllMain上使用这些的唯一原因是你想使用自己的运行时库(如果你想要更小的文件大小或自定义function)
对于自定义运行时实现和其他获取较小PE文件的技巧,请参阅:
Expert C ++ / CLI (请参阅第279页)有关于本机,混合和纯CLR程序集的不同引导方案的非常具体的详细信息。
它取决于操作系统。 在OS X中,mach头中有一个包含EIP(指令指针)寄存器起始地址的帧。
加载二进制文件后,操作系统将从此地址启动执行:
cristi:测试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 ___progname 00001fe0 t __dyld_func_lookup 00001000 A __mh_execute_header [..] 00001f8c T开始
在Mac OS X中,它是首先调用的“start”函数,甚至在“main”函数之前:
(gdb)b开始 断点1在0x1f90 (gdb)b主要 断点2在0x1ff4 (gdb)r 启动程序:/Users/diciu/Programming/test/a.out 读取共享库的符号++。 DONE start()中的断点1,0x00001f90
如果您对与Windows和Win32 API相关的书感兴趣,请尝试
Jeffrey Richter编写的“Microsoft Windows编程应用程序”。
您可以查看以下链接:
- 主function
- 入口点
- Microsoft特定主要