gcc生成执行文件过程为:源文件(*.c文件)编译成对象文件(*.o文件);
链接程序ld,把对象文件(*.o文件)链接成可执行程序。
因此要透彻链接的过程, 需要先了解对象文件(*.o文件)是怎样构成的?
下面用个简单的例子来说明:
#includeint global_var=5;extern int other_file_var;int main(){ int a=1;
int b=a other_file_var; return 0;
}gcc -c test.c -o test.o 生成test.o;
查看test.o内容(vim test.o):

图1
看到的是一堆乱码,因为查看方式不对, 就像mp3格式的文件需要用音乐播放器才能播放一样,对象文件(*.o)是elf格式的, 需要用objdump, readelf 工具来查看。
从elf格式的官方文档,可以了解到elf格式文件的结构如下图所示:
图2
下面将一个个部分来分析。
1. ELF文件头(Header)分析
readelf -h test.o查看elf文件头部信息
主要字段的含义已在图中标识;
由Size of this headers可知,头部占用了64字节;
用hexdump -n 64 test.o 查看头部64字节数据内容(16进制格式);图中红框里的数据就是test.o文件的前64字节,也就是elf头部,对比上面两图,(图1)中的魔数7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 刚好与(图2)中的前16字节(小段编码)对应,后面每个字段的含义也是一一对应的;
头部信息结构可以参考/usr/include/elf.h 里ELf64_Ehdr, 32位的可以参考ELf32_Ehdr结构typedef struct{
unsigned char e_ident[EI_NIDENT];
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx; } Elf64_Ehdr;由字段Start Of Section Header可知,在test.o文件的656字节处有一个'段的头部表'。
2. ELF段头部表(Section Header)分析
用readelf -S test.o查看'段的头部表',在这个表里保存了文件里所有段的属性信息,如段的名字,段在文件的开始位置, 段的长度等:
图4
由图可知主要字段的含义已从图中标识;
段表的数据在偏离文件开始的0x290处,跟ELF Header Start Of Section Header字段保持一致;
这个段表里总共有12项,不同的项描述了不同段的属性;
2.1 text段
text段在偏离test.o文件开头0x40字节处,长度为0x20字节,用hexdump -s 0x40 -n 0x20 test.o,查看text段的16进制内容。
图5
然后objdump -d test.o 打印出程序的反汇编代码,
图6
由上面两图可知,text部分的数据恰好是main函数的机器码,也就是text段里保存的是代码段。
2.2 data段
data段在偏离test.o文件开头0x60字节处,长度为0x4字节,用hexdump -s 0x60 -n 0x4 test.o,查看data段的16进制内容,
图7
4个字节刚好是个int的长度,里面保存的数值是5,也就是全局变量global_var的值,验证了已初始化的全局变量保存在data段。
2.3 bss段
2.4 .rela.text (text的重定位段)
main函数里的global_var定义在别的文件,后面链接需要根据别的文件来确定它的虚拟内存地址,由于text中有需要重定位的变量,所以就有了.rela.text段。readelf -r test.o
图8
offset列表示需要重定位的符号在该段中的偏移,这里表示偏离text段0xd处;
info列高4个字节是该符号在.symtab中的索引,见下图;
图9
2.5 .symtab 符号表
图9
ndx列是该符号在段表中的索引:(1)比如global_var的索引为3,图4中索引3表示data段,
也就是说global_var这个符号在data段;(2)如果是“UND“则表示该符号定义在别的文件,需要重定位,重定位信息见“2.4 .rela.text”。
图10