C程序如何启动?
C程序如何启动?
main()
函数。最终。exec()
调用后开始运行的地方。在Linux系统上,这是.init
部分中的_init
。在此返回后,它跳转到入口点地址,即.text
部分中的_start
。main()
。#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
匹配:
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
的地址。objdump -s -j .init_array c-test
:c-test: file format elf64-x86-64
Contents of section .init_array:
3db8 40110000 00000000 @.......
_init
或其他任何函数,而是调用入口地址。入口地址可以是任何位置。 - Andrey最终它是操作系统。通常在真正的入口点和主函数之间有一些中介,这是由链接器插入的。
一些细节(与Windows相关):PE文件中有一个称为IMAGE_OPTIONAL_HEADER
的头,其中包含字段AddressOfEntryPoint
,这又是文件中将要执行的第一个代码字节的地址。
crt.a(crt.o)
жҲ–crt.lib(crt.obj)
иҝҷж ·зҡ„дёңиҘҝжқҘе®һзҺ°зҡ„пјҢиҖҢиҝҷйҖҡеёёжҳҜзұ»дјјдәҺlibc.a
жҲ–c.lib
зҡ„дёҖйғЁеҲҶгҖӮ - Christian Hujer你的问题可能最好的信息可以在下面提到的链接中找到,http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html,这是我迄今为止发现的最好的一个。
请注意,除了已发布的答案外,您也可以自己调用main
函数。一般来说,这是一个保留给混淆代码的坏主意。