Contents
链接¶
链接(linking)是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载到存储器并执行。链接可以执行于编译时(compile time),也可以执行于加载时(load time),甚至执行于运行时(run time)。
链接器在软件开发中扮演着一个关键的角色,因为它们使得分离编译(separate compilation)成为可能。
静态链接¶
以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。

为了创建可执行文件,链接器必须完成两个主要任务:
- 符号解析(symbol resolution),将一个符号引用和一个符号定义结合起来。
- 重定位(relocation),编译器和汇编器生成从地址 0 开始的代码和数据节。链接器通过把每个符号定义域一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而重定位这些节。
目标文件纯粹是字节块的集合。这些块中,有些包含程序代码,有些则包含程序数据,而其他的则包含指导链接器和加载器的数据结构。链接器将这些块连接起来,确定被连接块的运行时位置,并且修改代码和数据块中的各种位置。链接器对目标机器了解甚少。产生目标文件的编译器和汇编器已经完成了大部分工作。
目标文件¶
目标文件有三种形式:
- 可重定位目标文件,包含二进制文件和代码,其形式在编译时和其他可重定位目标文件合并起来,创建一个可执行目标文件。
- 可执行目标文件,其形式可被拷贝到存储器并执行。
- 共享目标文件,一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载到存储器并链接。
编译器和汇编器生成可重定位目标文件(包括共享目标文件),链接器生成可执行目标文件。
符号和符号表¶
每个重定位的目标模块 m 都有一个符号表,包含 m 所定义和引用的符号的信息。在链接器的上下文中,有三种不同的符号:
- 有 m 定义并能够被其他模块引用的全局符号。
- 由其他模块定义并被 m 所引用的全局符号。
- 只被 m 定义和引用的本地符号。
C 程序员使用 static 属性在模块内部隐藏变量和函数声明。
符号解析¶
链接器解析符号引用的方法是将每个引用与它输入的可重定位目标文件的符号表中的一个确定的符号定义联系起来。
当编译器遇到一个不是在当前模块中定义的符号(变量或函数名)时,它会假设符号是在其他模块中定义的,生成一个链接器符号表表目,并把它交给链接器处理。
链接器如何解析多处定义的全局符号¶
编译器输出每个全局符号给汇编器,或者是强(stong),或者是弱(week),而汇编器把这些信息隐含得编码在可重定位目标文件的符号表里。函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。
根据强弱符号的定义,Unix 使用以下规则来处理多处定义的符号:
- 不允许有多个强符号。
- 如果有一个强符号和多个弱符号,则选择强符号。
- 如果有多个弱符号,则从中随机选择一个。




