跳转至

Chapter 7 Linking

约 811 个字 预计阅读时间 3 分钟

链接/Linking 是将各种代码和数据片段收集并且组合成一个单一文件的过程,这个文件可以被加载(也就是复制)到内存并且执行。链接可以发生在编译时/Compile Time;也可以发生在加载时/Load Time,也就是程序被加载器/Loader 加载到内存并执行时;还可以发生在运行时/Run Time。现代操作系统中,链接是由链接器/Linker 自动执行的。

7.1 编译器驱动程序

大多数编译系统都提供编译器驱动程序/Compiler Driver,它代表用户在需要时调用语言预处理器、编译器、汇编器和链接器,比如 gcc -Og -o prog main.c sum.c,就可以将 main.csum.c 编译、汇编、链接成一个可执行文件 prog

首先编译器驱动程序会先运行 C 预处理器/cpp,这期间会对源代码进行宏替换、头文件包含、条件编译与注释删除等等操作,比如下面的命令 cpp [args] main.c -o tmp/main.i 就将 main.c 预处理后的结果保存到 tmp/main.i 文件中。

之后驱动程序运行 C 编译器/cc1,将预处理后的文件 tmp/main.i 编译成 ASCII 汇编语言文件 tmp/main.scc1 tmp/main.i -Og [args] -o tmp/main.s

然后驱动程序运行汇编器/as,将汇编语言文件 tmp/main.s 汇编成可重定位文件/Relocatable Object File tmp/main.oas [args] -o tmp/main.o tmp/main.s

驱动程序经过相同的过程生成 sum.o,然后运行链接器程序 ldmain.osum.o 以及一些必要的系统目标文件组合起来,形成一个可执行目标文件/Executable Object File progld -o prog [other complex args and files] tmp/main.o tmp/sum.o

最后执行 ./prog,shell 会调用操作系统中的一个叫做加载器/Loader 的函数,将可执行文件的内容复制到内存中并将控制转移到这个程序的开头。

7.2 静态链接

7.3 目标文件

目标文件一共有三种形式:

  • 可重定位目标文件:包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件;
  • 可执行目标文件:包含二进制代码和数据,可以被复制到内存并执行;
  • 共享目标文件:一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态地加载进内存并链接。

编译器和汇编器生成可重定位目标文件和共享目标文件,链接器生成可执行目标文件。在 Linux 和 Unix 上,目标文件的格式是可执行可链接格式(Executable and Linkable Format,ELF),而在 Windows 上,目标文件的格式是可移植可执行格式(Portable Executable,PE)。

7.4 可重定位目标文件

7.5 符号和符号表

7.6 符号解析

7.7 重定位

7.8 可执行目标文件

7.9 加载可执行目标文件

7.10 动态链接共享库

7.11 从应用程序中加载和链接共享库

7.12 位置无关代码

7.13 库打桩机制

7.14 处理目标文件的工具