gpt4 book ai didi

c - 在 C 中,main() 方法最初是如何调用的?

转载 作者:太空狗 更新时间:2023-10-29 16:18:21 26 4
gpt4 key购买 nike

C 程序如何启动?

最佳答案

操作系统调用main()函数。最终。

Executable and Linkable Format (ELF)许多 Unix 操作系统的使用定义了一个入口点地址和一个 INIT 地址。这是操作系统完成其 exec() 调用后程序开始运行的地方。在 Linux 系统上,这是 .init 部分中的 _init。返回后,它跳转到入口点地址,即 .text 部分中的 _start

C 编译器将标准库链接到提供这些操作系统定义的初始化和入口点的每个应用程序。然后该库调用 main()

这是我的例子的 C 源代码:

#include <stdio.h>

int main() {
puts("Hello world!");
return 0;
}

来自 objdump -d:

Disassembly of section .init:

0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 callq *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 retq

Disassembly of section .text:

0000000000001060 <_start>:
1060: f3 0f 1e fa endbr64
1064: 31 ed xor %ebp,%ebp
1066: 49 89 d1 mov %rdx,%r9
1069: 5e pop %rsi
106a: 48 89 e2 mov %rsp,%rdx
106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1071: 50 push %rax
1072: 54 push %rsp
1073: 4c 8d 05 66 01 00 00 lea 0x166(%rip),%r8 # 11e0 <__libc_csu_fini>
107a: 48 8d 0d ef 00 00 00 lea 0xef(%rip),%rcx # 1170 <__libc_csu_init>
1081: 48 8d 3d c1 00 00 00 lea 0xc1(%rip),%rdi # 1149 <main>
1088: ff 15 52 2f 00 00 callq *0x2f52(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5>
108e: f4 hlt
108f: 90 nop

0000000000001140 <frame_dummy>:
1140: f3 0f 1e fa endbr64
1144: e9 77 ff ff ff jmpq 10c0 <register_tm_clones>

readelf -h可以看到匹配_start的Entry point地址:

ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1060
Start of program headers: 64 (bytes into file)
Start of section headers: 17416 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 36
Section header string table index: 35

来自 readelf -d:

Dynamic section at offset 0x2dc8 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x1000
0x000000000000000d (FINI) 0x11e8
0x0000000000000019 (INIT_ARRAY) 0x3db8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x3dc0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x3a0
0x0000000000000005 (STRTAB) 0x470
0x0000000000000006 (SYMTAB) 0x3c8
0x000000000000000a (STRSZ) 130 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x3fb8
0x0000000000000002 (PLTRELSZ) 24 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x5e0
0x0000000000000007 (RELA) 0x520
0x0000000000000008 (RELASZ) 192 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0x500
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x4f2
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0

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

INIT_ARRAY 中也有一个完整的函数指针数组。请参阅 objdump -s -j .init_array c-test:

c-test:     file format elf64-x86-64

Contents of section .init_array:
3db8 40110000 00000000 @.......

可以看到地址0x3db8和ELF头中的INIT_ARRAY是一样的。

地址 0x1140(记住从 40110000 开始的小端字节布局)是您可以在反汇编中看到的函数 frame_dummy。然后调用 register_tm_clones,谁知道还有什么。

初始化代码位于一组名为 crtbegin.o 和 crtend.o(以及这些名称的变体)的文件中。 __libc_start_main 函数在 libc.so.6 中定义。这些库是 GCC 的一部分。该代码执行 C 程序所需的各种操作,例如设置标准输入、标准输出、全局和静态变量以及其他操作。

下面的文章很好地描述了它在 Linux 中的作用(摘自以下投票较少的答案):http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html

我相信其他人的回答已经描述了 Windows 的作用。

关于c - 在 C 中,main() 方法最初是如何调用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3469955/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com