目录
1 概述
2 程序编译
3 揭开最后的面纱
1 概述
学习C语言的同学都知道main函数,并且这是我们接触的第一个函数,但是很少有人去深究C语言为什么都是从main函数执行的。今天我们就来深入了解下。
2 程序编译
C语言生成可执行文件分为3个阶段:编译、链接、运行。每个编辑单元(例如多个.c源文件)是各自独立编译成目标文件(例如.o),最后由链接器把这些目标文件链接成可执行程序。
3 揭开最后的面纱
实际上使用gcc进行链接时要调用下面的命令:
ld /usr/lib/crt1.o /usr/lib/crti.o main.o -o main -lc -dynamic-linker /lib/ld-linux.so.2
main.o 需要和 crt1.o,crti.o 这两个目标文件链接在一起,从而生成可执行文件 main。你可以使用 readelf 命令来查看 crt1.o 文件的符号表,就会发现里面有一个 main 符号是未定义的,因此需要别的目标文件提供一个定义并且和 crt1.o 链接在一起(在 crt1.o 中要用到 main 这个符号所代表的地址,而 crt1.o 中的未定义符号 main 在 main.o 中定义了)。
下面看下crt1.o中的符号表:
parallels@ubuntu-linux-20-04-desktop:/usr/lib/aarch64-linux-gnu$ readelf -a crt1.o
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: REL (Relocatable file)
Machine: AArch64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 1064 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 11
Section header string table index: 10
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.ABI-tag NOTE 0000000000000000 00000040
0000000000000020 0000000000000000 A 0 0 4
[ 2] .text PROGBITS 0000000000000000 00000060
000000000000003c 0000000000000000 AX 0 0 4
[ 3] .rela.text RELA 0000000000000000 000002f0
00000000000000d8 0000000000000018 I 8 2 8
[ 4] .rodata.cst4 PROGBITS 0000000000000000 0000009c
0000000000000004 0000000000000004 AM 0 0 4
[ 5] .data PROGBITS 0000000000000000 000000a0
0000000000000004 0000000000000000 WA 0 0 1
[ 6] .bss NOBITS 0000000000000000 000000a4
0000000000000000 0000000000000000 WA 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 000000a4
0000000000000000 0000000000000000 0 0 1
[ 8] .symtab SYMTAB 0000000000000000 000000a8
00000000000001e0 0000000000000018 9 11 8
[ 9] .strtab STRTAB 0000000000000000 00000288
0000000000000067 0000000000000000 0 0 1
[10] .shstrtab STRTAB 0000000000000000 000003c8
000000000000005c 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
Relocation section '.rela.text' at offset 0x2f0 contains 9 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000018 000100000113 R_AARCH64_ADR_PRE 0000000000000000 .text + 38
00000000001c 000100000115 R_AARCH64_ADD_ABS 0000000000000000 .text + 38
000000000020 000e00000113 R_AARCH64_ADR_PRE 0000000000000000 __libc_csu_init + 0
000000000024 000e00000115 R_AARCH64_ADD_ABS 0000000000000000 __libc_csu_init + 0
000000000028 000b00000113 R_AARCH64_ADR_PRE 0000000000000000 __libc_csu_fini + 0
00000000002c 000b00000115 R_AARCH64_ADD_ABS 0000000000000000 __libc_csu_fini + 0
000000000030 00120000011b R_AARCH64_CALL26 0000000000000000 __libc_start_main + 0
000000000034 000c0000011b R_AARCH64_CALL26 0000000000000000 abort + 0
000000000038 000f0000011a R_AARCH64_JUMP26 0000000000000000 main + 0
The decoding of unwind sections for machine type AArch64 is not currently supported.
Symbol table '.symtab' contains 20 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 SECTION LOCAL DEFAULT 2
2: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 $d
3: 0000000000000000 0 NOTYPE LOCAL DEFAULT 2 $x
4: 0000000000000038 0 NOTYPE LOCAL DEFAULT 2 __wrap_main
5: 0000000000000000 0 NOTYPE LOCAL DEFAULT 4 $d
6: 0000000000000000 0 SECTION LOCAL DEFAULT 1
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
8: 0000000000000000 0 SECTION LOCAL DEFAULT 5
9: 0000000000000000 0 SECTION LOCAL DEFAULT 6
10: 0000000000000000 0 SECTION LOCAL DEFAULT 7
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __libc_csu_fini
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND abort
13: 0000000000000000 0 FUNC GLOBAL DEFAULT 2 _start
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __libc_csu_init
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND main
16: 0000000000000000 0 NOTYPE WEAK DEFAULT 5 data_start
17: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 _IO_stdin_used
18: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __libc_start_main
19: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 5 __data_start
事实上,整个可执行程序真正的入口点是 crt1.o 中的 _start,而 main 函数是被 _start 调用的。
×