编译链接过程
代码
#cat main.c
#include <stdio.h>
int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);
int main(void)
{
printf("add:%d\n", add(1,2));
printf("sub:%d\n", sub(10,100));
printf("mul:%d\n", mul(5,10));
printf("div:%d\n", div(200,100));
return 0;
}
===
#cat math.c
#include <stdio.h>
int add(int x, int y)
{
return (x + y);
}
int sub(int x, int y)
{
return (x - y);
}
int mul(int x, int y)
{
return (x * y);
}
int div(int x, int y)
{
return (x/y);
}
预处理:
#gcc -E main.c -o main.i
编译: 生成.s 文件
#gcc -c main.c math.c
#ls main.s math.s
main.s math.s
汇编:生成.o 文件(可重定位目标文件)
#gcc -c main.c math.c
#ls main.o math.o
main.o math.o
链接:生成 (可执行目标文件)
#gcc -o main.out main.o math.o
目标文件
分三种:
- 可重定位目标文件 (Relocatable file) (.o 文件,没有被链接的)
- 可执行目标文件 (Executable file)(.out文件 最终二进制文件)
- 可被共享目标文件 (Shared object file) (.so 结尾的)
看ELF的常见命令:
ELF文件格式需要知道;
#readelf -h main.out 看ELF文件的header部分
#readelf -S main.out 看ELF文件的Section header
#readelf -h main.out
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: EXEC (Executable file) // 可执行文件
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400430 // 函数入口地址
Start of program headers: 64 (bytes into file)
Start of section headers: 6720 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 27
#readelf -h main.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: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0 // 所以,这里看函数入口地址为0
Start of program headers: 0 (bytes into file)
Start of section headers: 1152 (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: 13
Section header string table index: 10
静态库:
静态库: (.a 结尾的) 从 .o 文件而来
//生成静态库 : 使用ar命令,将.o 生成.a 文件。这里名字有讲究的, lib + math + .a 中间的才是库名字。
#ar rcs libmath.a math.o
// 使用静态库: -L 表示路径, -l 表示库的名字
#gcc main.o -L. -l math -o main.out
#./main.out
add:3
sub:-90
mul:50
div:2
其实和.o 文件差距不大,都是 重定向文件,只不过做了归档。
#readelf -h libmath.a
File: libmath.a(math.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: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 840 (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: 8
共享库:
共享库: (.so 结尾的)
#gcc --shared -fPIC -o libmath.so math.c
#ll libmath.so
-rwxr-xr-x 1 root root 7864 Feb 1 16:21 libmath.so
类型: Shared object file
#readelf -h libmath.so
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: 0x5b0
Start of program headers: 64 (bytes into file)
Start of section headers: 6216 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 7
Size of section headers: 64 (bytes)
Number of section headers: 27
Section header string table index: 24
GCC
gcc 不是一个简单的命令,里面有很多库
[root@r10n04359.sqa.zmf /usr/lib/gcc/x86_64-redhat-linux/6.4.0]
#ls
32 crtendS.o finclude libcaf_single.a libgcc_s.so libgomp.so libmpx.spec libstdc++.so
crtbegin.o crtfastmath.o include libcilkrts.so libgcov.a libgomp.spec libmpxwrappers.so libtsan.so
crtbeginS.o crtprec32.o libasan_preinit.o libcilkrts.spec libgfortran.so libitm.spec libquadmath.so libubsan.so
crtbeginT.o crtprec64.o libasan.so libgcc.a libgfortran.spec liblsan.so libsanitizer.spec rpmver
crtend.o crtprec80.o libatomic.so libgcc_eh.a libgomp.a libmpx.so libstdc++fs.a
链接阶段
符号表
几个简单命令,不要混淆:
#readelf -S math.o // 查看Section header
#readelf -s math.o // 查看symble table
#readelf -h math.o // 查看ELF 的header(主要存放一些,ELF文件的类型,架构之类的)
查看Section header
一个ELF 的section 有哪些?
大家都知道的.text, .data, .bss 等section
#readelf -S math.o
There are 11 section headers, starting at offset 0x348:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
000000000000004c 0000000000000000 AX 0 0 1
[ 2] .data PROGBITS 0000000000000000 0000008c
0000000000000000 0000000000000000 WA 0 0 1
[ 3] .bss NOBITS 0000000000000000 0000008c
0000000000000000 0000000000000000 WA 0 0 1
[ 4] .comment PROGBITS 0000000000000000 0000008c
000000000000002d 0000000000000001 MS 0 0 1
[ 5] .note.GNU-stack PROGBITS 0000000000000000 000000b9
0000000000000000 0000000000000000 0 0 1
[ 6] .eh_frame PROGBITS 0000000000000000 000000c0
0000000000000098 0000000000000000 A 0 0 8
[ 7] .rela.eh_frame RELA 0000000000000000 00000290
0000000000000060 0000000000000018 I 9 6 8
[ 8] .shstrtab STRTAB 0000000000000000 000002f0
0000000000000054 0000000000000000 0 0 1
[ 9] .symtab SYMTAB 0000000000000000 00000158
0000000000000120 0000000000000018 10 8 8
[10] .strtab STRTAB 0000000000000000 00000278
0000000000000018 0000000000000000 0 0 1
查看Symbol table
虽然,你可以看到 math.c 中的add, sub, mul, div 这些符号表的名字,但是,这个符号表不存在这里,是通过索引获取的。 实际上是存在.strtab
这个section中的。
#readelf -s math.o
Symbol table '.symtab' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS math.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 4
8: 0000000000000000 20 FUNC GLOBAL DEFAULT 1 add
9: 0000000000000014 18 FUNC GLOBAL DEFAULT 1 sub
10: 0000000000000026 19 FUNC GLOBAL DEFAULT 1 mul
11: 0000000000000039 19 FUNC GLOBAL DEFAULT 1 div