在C/C++程序中系统(windows、linux、mac OS X)如何调用main()函数
题
我正在寻找比操作系统调用该函数更技术性的解释。任何人都可以帮助我或向我指出网站或书籍吗?
解决方案
.exe 文件(或其他平台上的等效文件)包含一个“入口点”地址。初步估计,操作系统将 .EXE 文件的相关部分加载到 RAM 中,然后跳转到入口点。
正如其他人所说,这个入口点不会是“main”,而是成为运行时库的一部分 - 它将执行初始化静态对象、设置 argc/argv 参数、设置 stdin/stdout/stderr 等操作, ETC。完成所有这些后,它将调用您的 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 文件的其他技巧,请参阅:
专家 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 flavor i386_THREAD_STATE count 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 start
在 Mac OS X 中,首先调用的是“start”函数,甚至在“main”函数之前:
(gdb) b start Breakpoint 1 at 0x1f90 (gdb) b main Breakpoint 2 at 0x1ff4 (gdb) r Starting program: /Users/diciu/Programming/test/a.out Reading symbols for shared libraries ++. done Breakpoint 1, 0x00001f90 in start ()
如果您对与 Windows 和 Win32 API 相关的书籍感兴趣,请尝试
Jeffrey Richter 的“Microsoft Windows 编程应用程序”。