
静态链接
将可重定位目标文件链接为可执行目标文件。 两个主要任务:
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量。将每个符号引用正好与一个符号定义关联起来。
- 重定位:编译器和汇编器生成从地址 0 开始的代码和数据节,链接器将多个文件的数据和代码集成为单一的数据段和代码段,把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
目标文件
三种形式:
- 可重定位目标文件
.o:包含二进制代码和数据,可以与其他.o文件集成为可执行目标文件。 - 可执行目标文件
.out:包含二进制代码和数据,可直接被复制到内存中执行。 - 共享目标文件
.so:特殊类型的可重定位目标文件,可在运行时被动态地加载进内存并链接。
可重定位目标文件
ELF 文件格式
- ELF Header:描述基本信息,如机器字长度、字节序、机器类型、目标文件类型等
.text:已编译程序的机器代码.rodata:只读数据,常量字符串和跳转表等.data:已初始化的全局和静态变量.bss:未初始化或被初始化为 0 的全局和静态变量.symtab:符号表,存放在程序中定义和引用的函数和全局变量的信息.rel.text:.text段的重定位信息。 一个.text节中位置的列表,当链接器把这个目标文件和其他文件组合时,需要修改这些位置,可执行目标文件中通常省略.rel.data:.data段的重定位信息。.debug:调试符号表- 节头部表:描述不同节的位置和大小
符号和符号表
- 全局符号:某一个模块定义,可以被其他模块引用的变量或函数符号,比如非静态函数和全局变量
- 外部符号:由其他模块定义,该模块引用的全局符号
- 局部符号:由某个模块定义,且仅由该模块引用的符号,比如静态全局变量或函数
符号解析
多重定义的全局符号的解析
- 强符号:过程和初始化的全局变量
- 弱符号:未初始化的全局变量
- 不允许使用多个同名强符号
- 存在一个强符号和多个弱符号同名,选择强符号
- 有多个弱符号同名,任意选择一个
与静态库的链接
将一系列目标模块打包为一个静态库文件,链接时,链接器只复制被程序引用的目标模块。
链接时命令行上的库和目标文件的顺序非常重要,在遇到库时,只会搜索前缀中未定义的引用,因此最好把库放在命令末尾,若多个库不相互独立,还需要对它们进行排序。
重定位
- 重定位节和符号定义:将所有相同类型的节合并为同一类型的新的节,将运行时内存地址赋给新的节
- 重定位节中的符号引用:修改代码节和数据节中对每个符号的引用,使它们指向正确的运行时地址,这依赖于重定位条目
重定位条目
offset:需要被修改的引用的偏移 (对应指令中的占位符的起始地址)type:重定位类型symbol:被修改引用指向的符号addend:偏移调整 重定位类型type:R_X86_64_PC32:重定位一个使用 32 位 PC 相对地址的引用R_X86_64_32:重定位一个使用 32 位绝对地址的引用