18

我正在寻找更技术性的解释,然后操作系统调用该函数。

任何人都可以帮助我或将我指向一个网站或书籍吗?

4

5 回答 5

26

.exe 文件(或其他平台上的等效文件)包含一个“入口点”地址。大致上,操作系统将 .EXE 文件的相关部分加载到 ram 中,然后跳转到入口点。

正如其他人所说,这个入口点不会是“main”,而是运行时库的一部分——它会做一些事情,比如初始化静态对象、设置 argc/argv 参数、设置 stdin/stdout/stderr等。完成所有这些后,它将调用您的 main() 函数。当 main 退出时,运行时会经历一个类似的过程,将返回代码传回环境,调用静态析构函数,调用 _atexit 例程等。

如果你有 MS 工具(也许不是免费的),那么你就有了所有运行时源代码,查看它的一种简单方法是在 main() 方法的右大括号上放置一个断点,然后单步备份进入运行时。

于 2008-08-15T15:50:12.457 回答
8

main()是 C 库的一部分,不是系统函数。我不知道 OS X 或 Linux,但 Windows 通常以WinMainCRTStartup(). 此符号初始化您的进程,提取命令行参数和环境 ( argc, argv, end) 并调用main()。它还负责调用应该在之后运行的任何代码main(),例如atexit().

通过查看您的 Visual Studio 文件,您应该能够找到 的默认实现WinMainCRTStartup以了解它的作用。

您还可以定义自己的函数以在启动时调用,这是通过更改链接器选项中的“入口点”来完成的。这通常是一个不带参数并返回 void 的函数。

于 2008-08-15T15:19:16.713 回答
5

就 Windows 而言,入口点功能是:

  • 安慰:void __cdecl mainCRTStartup( void ) {}
  • 图形用户界面:void __stdcall WinMainCRTStartup( void ) {}
  • 动态链接库:BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {}

使用这些而不是普通的 main/WinMain/DllMain 的唯一原因是如果您想使用自己的运行时库(如果您想要更小的文件大小或自定义功能)

有关自定义运行时实现和其他获取更小的 PE 文件的技巧,请参阅:

于 2008-08-28T20:23:52.437 回答
1

Expert C++/CLI(查看第 279 页)有非常具体的关于本机、混合和纯 CLR 程序集的不同引导方案的详细信息。

于 2008-08-15T16:35:07.403 回答
1

它取决于操作系统。在 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()
于 2008-08-27T18:40:29.043 回答