在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特定主要