操作系统-在C语言中,最初如何调用main()方法?

C程序如何开始?

user418627 asked 2020-01-23T23:16:09Z
7个解决方案
48 votes

操作系统调用exec()函数。 实际上,它通常调用诸如_init之类的名为“陌生事物”的事物。C编译器将标准库链接到每个提供此操作系统定义的入口点的应用程序,然后调用main()

编辑:显然,这对于某些人来说不够详细和正确。

许多Unix OS使用的可执行和可链接格式(ELF)定义了入口点地址。 在操作系统完成其exec()调用之后,程序即开始在该位置运行。 在Linux系统上,这是_init。

从objdump -d:

Disassembly of section .init:

08049f08 <_init>:
 8049f08:       55                      push   %ebp
 8049f09:       89 e5                   mov    %esp,%ebp
 8049f0b:       83 ec 08                sub    $0x8,%esp
 8049f0e:       e8 a1 05 00 00          call   804a4b4 <call_gmon_start>
 8049f13:       e8 f8 05 00 00          call   804a510 <frame_dummy>
 8049f18:       e8 d3 50 00 00          call   804eff0 <__do_global_ctors_aux>
 8049f1d:       c9                      leave  
 8049f1e:       c3                      ret    

从readelf -d:

 0x00000001 (NEEDED)                     Shared library: [libstdc++.so.6]
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libgcc_s.so.1]
 0x00000001 (NEEDED)                     Shared library: [libpthread.so.0]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x8049f08
 0x0000000d (FINI)                       0x804f018
 0x00000004 (HASH)                       0x8048168
 0x00000005 (STRTAB)                     0x8048d8c
 0x00000006 (SYMTAB)                     0x804867c
 0x0000000a (STRSZ)                      3313 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x8059114
 0x00000002 (PLTRELSZ)                   688 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x8049c58
 0x00000011 (REL)                        0x8049be0
 0x00000012 (RELSZ)                      120 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffe (VERNEED)                    0x8049b60
 0x6fffffff (VERNEEDNUM)                 3
 0x6ffffff0 (VERSYM)                     0x8049a7e
 0x00000000 (NULL)                       0x0

您可以看到INIT等于_init的地址。

frame_dummy和__do_global_ctors_aux的代码在一组名为crtbegin.o和crtend.o(以及这些名称的变体)的文件中。 这些是海湾合作委员会的一部分。 该代码执行C程序所需的各种操作,例如设置stdin,stdout,全局和静态变量以及其他操作。

以下文章很好地描述了它在Linux中的功能(从下面的答案中以较少的票数得出):[http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html]

我相信其他人的答案已经描述了Windows的功能。

Zan Lynx answered 2020-01-23T23:16:56Z
24 votes

最终它是操作系统。 通常,实际入口点和主函数之间存在某种介质,该介质由编译器链接程序插入。

一些细节(与Windows相关):PE文件中有一个名为IMAGE_OPTIONAL_HEADER的标头,该标头具有字段AddressOfEntryPoint,而该字段又是文件中将要执行的第一个代码字节的地址。

Andrey answered 2020-01-23T23:17:21Z
9 votes

[http://coding.derkeiler.com/Archive/C_CPP/comp.lang.c/2008-04/msg04617.html]

user387302 answered 2020-01-23T23:17:41Z
7 votes

操作系统调用main。 可重定位可执行文件中将有一个地址指向main的位置(有关更多信息,请参见Unix ABI)。

但是,谁叫操作系统?

中央处理单元在“ RESET”信号(在上电时也会断言)上,将开始在给定地址(例如0xffff)的某些ROM中查找其指令。

通常,会有一些跳转指令发送到BIOS,该指令用于配置内存芯片,加载基本的硬盘驱动器等,然后读取硬盘驱动器的Boot Sector,然后启动下一个Bootloader, 它将加载包含有关如何读取(例如,NTFS分区)以及如何读取内核文件本身的基本信息的文件。 将设置内核环境,加载内核,然后-然后! -内核将跳至执行。

完成所有艰苦的工作后,内核即可继续加载我们的软件。

Paul Nathan answered 2020-01-23T23:18:20Z
5 votes

操作系统调用C运行时(CRT)中包含的函数,并链接到您的可执行文件中。 将此称为“ CRT主管道”。

CRT main做一些事情,至少在C ++中,这两项最重要的事情是遍历一组全局C ++类并调用它们的构造函数,并调用main()函数并将其返回值提供给shell 。

如果有内存,Visual C ++ CRT主干器还会做其他一些事情。 它配置内存分配器,如果使用“调试CRT”来帮助查找内存泄漏或错误访问,则很重要。 它还在结构化异常处理程序中调用main,以捕获不良的内存访问和其他崩溃并显示它们。

Drew Hoskins answered 2020-01-23T23:18:50Z
4 votes

请注意,除了已经发布的答案之外,您还可以自己致电main。 通常,这对于保留代码是一个坏主意。

Brian answered 2020-01-23T23:19:10Z
4 votes

可能在以下提到的链接中找到有关您问题的最佳信息[http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html,]迄今为止我遇到过的最好的。

Nandan Bharadwaj answered 2020-01-23T23:19:30Z
translate from https://stackoverflow.com:/questions/3469955/in-c-how-is-the-main-method-initially-called