链接简介
什么是链接
- 链接是将各种代码和数据片段收集并组合称为一个单一文件的过程,这个文件可被加载(复制)到内存并执行.
链接的时期
- 链接可以执行于编译时(源代码被翻译成机器代码时),加载时(程序被加载器加载到内存并执行时),运行时(程序运行的时候)
连接器
- 现代操作系统中,链接由连接器自动执行.
- 连接器使得程序可以分离编译
- 将大型程序分成一个个模块,单独编译,并进行链接.当需要修改某一模块时,只需重新编译某一模板并重新链接即可
编译器驱动程序(程序编译过程)
- 示例程序
```cpp
/code/link/main.c/
int sum(int *a,int n);
int array[2] = {1,2};
int main()
{
int val = sum(array,2);
return val;
}
```cpp
/* code/link/sum.c */
int sum(int *a,int n)
{
int i,s=0;
for(i = 0; i < n; ++i)
{
s+=a[i];
}
return s;
}
- 编译器驱动程序:用于调用语言预处理器、编译器、汇编器和链接器.
- 下图概括驱动程序将实例程序从ASCII码源文件翻译成可执行目标文件时的行为(静态链接).
- 上图的编译过程如下
- main.c通过C预处理器(cpp)将C的源程序翻译成ACII码的中间文件main.i
- main.i通过c编译器(cc1)将ACII码的中间文件翻译成ASCII汇编语言文件main.s
- main.s通过汇编器(as)将ASCII汇编语言文件翻译成可重定位目标文件main.o
- 所有.o文件和一些必要的系统目标文件通过连接器程序(ld)组合起来创建一个可执行目标文件
静态链接
- 什么是静态链接?
- 静态链接是静态链接器以一组
可重定位目标文件
和命令行参数
作为输入,生成一个完全链接的
、可以加载
和运行
的可执行目标文件作为输出.- 可重定位文件由不同的代码和数据节组成,每一节都是一个连续的字节序列.
- 指令,初始化的全局变量,未初始化的变量在不同的节中.
- 可重定位文件由不同的代码和数据节组成,每一节都是一个连续的字节序列.
- 静态链接是静态链接器以一组
连接器的主要任务
- 符号解析
- 任务:目标文件定义和引用符号
- 每个符号对应一个函数、一个全局变量或一个静态变量
- 任务:目标文件定义和引用符号
目的:将每个符号引用正好和一个符号定义关联起来.
重定位:
- 任务:编译器和汇编器生成从地址0开始的代码和数据节.
- 目的:
- 连接器将符号定义与内存位置进行关联.然后修改这些符号的引用,使它们指向相应的内存位置.
- 链接器使用汇编器产生的重定位条目的详细指令,不加甄别地执行这样的重定位.
- 符号解析
目标文件
- 可重定位目标文件:包含二进制代码和数据,可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件.
- 可执行目标文件:包含二进制代码和数据,可以直接复制到内存并执行.
- 共享目标文件:特殊的可重定位目标文件,可以在加载或者运行时被动态地加载进内存并链接
- 其中编译器和汇编器生成可重定位目标文件和共享目标文件,连接器生成可执行目标文件
- 目标模块:一个字节序列
- 目标文件:一个以特定的文件形式存放在磁盘中的目标模块
可重定位目标文件
elf可重定位目标文件字段说明
- ELF头:
- 生成该文件袋系统的字的大小和字节顺序(小端、大端)(16B)
- 帮助连接器语法分析和解释目标文件的信息.
- ELF头的大小,目标文件类型,机器类型(e.g. x86-64),节头部表的文件偏移,节头部表中条目的大小和数量.
- 节头部表:描述不同节的位置和大小.
- .text:已经编译的程序代码.
- .rodata:只读数据
- 字符常量或者switch的转跳表
- .data:已经初始化的全局和静态变量,局部变量保存在栈中.
- .bss:未初始化的全局和静态变量,以及被初始化为0的全局或静态变量.
- 在目标文件中改节不占实际的空间,仅仅是一个占位符.
- 目的:提高空间效率,在磁盘中不占空间,在内存中初始化为0
- .symtab:符号表,存放程序中定义和引用的函数和全局变量(包括静态变量)的信息.
- -g编译命令可以得到符号表,还包含局部变量
- .symtab中的符号表不包含局部变量的条目
- .rel.text:.text节相关的可重定位信息.
- 当连接器将某个目标文件和其他目标文件组合式,.text节中的代码会被合并,相应的一些指令中引用的操作数地址信息或跳转目标指令信息等可能要被修改.
- 一般调用外部函数或者引用全局变量的指令中的地址字段需要修改.
- .rel.data:.data节相关的可重定位.
- 当连接器将某个目标文件和其他目标文件组合式,.data节中的代码会被合并,一些全局变量的地址可能被修改.
- .debug:调试符号表
- .line:原始c源程序的行号和.text节中机器指令之间的映射.(需要-g选项)
- .strtab:字符串表