第七章 链接 ——《深入理解计算机系统》
链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行。
一、编译器
大多数编译系统提供编译驱动程序,它代表用户在需要时调用语言预处理器、编译器、汇编器和链接器。链接可以执行于编译时,也就是在源代码被翻译成机器代码时;也可以执行于加载时,也就是在程序被加载器加载到存储器并执行时;甚至执行于运行时,由应用程序来执行。
二、静态链接器
像Unix ld程序这样的静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。输入的可重定位目标文件由各种不同的代码和数据节组成。指令在一个节中,初始化的全局变量在另一个节中,而未初始化的变量又在另外一个节中。
1.链接器有两个主要任务:
符号解析: 目标文件定义和引用符号。符号解析的目的是将每个符号引用刚好和一个符号定义联系起来。重定位: 编译器和汇编器生成从地址0开始的饿代码和数据节。链接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而重定位这些节。
2.链接器的属性:目标文件纯粹是字节块的集合。
这些块中,有些包含程序代码,有些则包含程序数据,而其他的则包含指导链接器和加载器的数据结构。链接器将这些块连接起来,确定被连接块的运行时位置,并且修改代码和数据块中的各种位置。链接器和汇编器已经完成了大部分工作。目标文件纯粹是字节快的集合。这些块中,有些包含程序代码,有些则包含程序数据,而其他的则包括指导链接器和加载器的数据结构。链接器将这些块链接起来,确定被连接块的运行时位置,并且修改代码和数据块中的各种位置。链接器对目标机器了解甚少。产生目标文件的编译器和汇编器已经完成了大部分工作。
三、目标文件
目标文件有三种形式:可重定位目标文件、可执行目标文件和共享目标文件。编译器和汇编器生成可重定位目标文件(包括共享目标文件)。链接器生成可执行目标文件。从技术上来说,一个目标模块就是一个字节序列,而一个目标文件就是一个存放在磁盘文件中的目标模块。编译器和汇编器生成可重定义目标文件(包括共享目标文件)。链接器生成可执行目标文件。各个系统之间,目标文件格式都不相同。
四、可重定位目标文件
ELF头以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位、可执行或是共享的)、机器类型、节头部表的文件偏移,以及节头部表中的条目大小和数量。不同的节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的条目。
五、符号和符号表
在链接器的上下文中,有三种不同的符号: 由m定义并能被其他模块引用的全局符号 由其他模块定义并被模块m引用的全局符号 只被模块m引用的本地符号
六、重定位
重定位的组成: 重定位节和符号定义。 重定位节中的符号引用。
七、可执行目标文件
可执行目标文件的格式类似于可重定位目标文件的格式。ELF头部描述文件的总体格式。ELF可执行文件被设计得很容易加载到存储器,可执行文件的连续的片被映射到连续的存储器段。段头部表描述了这种映射关系。
八、动态链接共享库
共享库是致力于解决静态库缺陷的一个现代创新产物。共享库是一个目标模块,在运行时,可以加载到任意的存储器地址,并加一个在存储器中的程序链接起来。这个过程称为动态链接,是由一个叫做动态链接器的程序来执行的。共享库也称为共享目标,在UNIX系统中通常用.so后缀来表示。