链接

可执行文件的生成

编译系统提供编译器驱动程序,包括了 预处理器,编译器,汇编器和链接器。

  • 预处理器(cpp)将C的源程序 foo.c 翻译成一个ASCII码的中间文件 foo.i

    shell> cpp [-args] foo.c /tmp/foo.i

  • C 编译器(ccl),将 foo.i 翻译成一个 ASCII 汇编语言文件 foo.S

    shell> ccl /tmp/foo.i [-args] -o /tmp/foo.S

  • 汇编器(as),将 foo.S 翻译成一个可重定位目标文件(relocatable object file)foo.o

    shell> as [-args] -o /tmp/foo.o /tmp/foo.S

  • 链接器(ld),将 foo.o 等别的可重定位目标文件和一些必要的系统文件组合起来,创建一个可执行文件(executable object)。

    shell> ld -o a.out [system object file and args] /tmp/foo.o /tmp/etc.o

  • 最后shell调用操作系统中一个称为加载器(loader)的函数,将可执行文件中的代码和数据复制到内存,然后将控制转移到这个程序的开头。

几个目标文件的形式

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

静态链接

静态链接器(static linker) 以一组可重定位目标文件和命令参数作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件作为输出。输入的可重定位目标文件由各种不同的代码和数据节(section)组成,每一节都是一个连续的字节序列。指令在一节中,初始化的全局变量在另一节中,而未初始化的变量又在另外一个节中。为了构造可执行文件,链接器必须完成两个主要任务。

  • 符号链接(symbol resolution)。目标文件定义和引用符号,每个符号对应于一个函数,一个全局变量或一个静态变量(C语言中任何以static属性声明的变量。符合解析的目的是将每个符合引用正好和一个符号定义关联起来
  • 重定位(relocation)。编译器和汇编器生成从地址0开始的代码和数据节。链接器通过把每个符号与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得他们只想这个内存位置。链接器使用汇编产生的重定位条目(relocation entry)的详细指令,不加判断的执行这样的重定位。