更新时间:2023-01-26 15:59
链接器(Linker)是一个程序,将一个或多个由编译器或汇编器生成的目标文件外加库链接为一个可执行文件。目标文件是包括机器码和链接器可用信息的程序模块。简单的讲,链接器的工作就是解析未定义的符号引用,将目标文件中的占位符替换为符号的地址。链接器还要完成程序中各目标文件的地址空间的组织,这可能涉及重定位工作。
到目前为止我们描述的内容表明,对于源程序任意一行代码的修改都需要重新编译和汇编整个程序,全部重新翻译是对计算资源的严重浪费。这种重复对于标准库程序尤为浪费,因为程序员要编译和汇编那些在定义上几乎从未改变过的过程。另一种方法是单独编译和汇编每个过程,以使得某一行代码的改变只需要编译和汇编一个过程。这种方法需要一个新的系统程序,称为链接编辑器(link editor)或链接器(linker),它把所有独立汇编的机器语言程序“拼接”在一起。
链接器也称链接编辑器,它是一个系统程序,把各个独立汇编的机器语言程序组合起来,并且解决所有未定义的标记,最后生成可执行文件。
链接器的工作分3个步骤:
1、将代码和数据模块象征性地放入内存。
2、决定数据和指令标签的地址。
3、修补内部和外部引用。
链接器使用每个目标模块中的重定位信息和符号表,来解析所有未定义标签。这种引用发生在分支指令、跳转指令和数据寻址处,所以这个程序的工作非常像一个编辑器:它寻找所有旧地址并用新地址取代它们:编辑是“链接编辑器”或链接器名字的简称。采用链接器的原因是修补代码比重新编译和汇编要快得多。
如果所有外部引用都解析完,链接器接着决定每个模块将要占用的内存位置。MlIPS在内存中为程序和数据分配空间的方式。因为文件是单独汇编的,所以汇编器不可能知道该模块的指令和数据相对于其他模块而言将会被放到哪里。当链接器将一个模块放到内存中的时候,所有绝对引用(absolute reference),即与寄存器无关的内存地址必须重定位以反映它的真实地址。
链接器产生一个可执行文件(executable file),它可以在一台计算机上运行。通常,这个文件与目标文件具有相同的格式,但是它不包含未解决的引用。具有部分链接的文件是可能的,如库程序,在目标文件中仍含有未解决的地址。
GNU的链接器称为ld,它负责把若干目标文件与若干库文件链接起来,并重定位它们的数据位置。在编译一个程序时,最后一步就是运行ld命令,通常ld直接由gcc负责调用,对用户程序员透明。ld能接受链接描述文件的控制,这是一种用链接命令语言(LinkerScript)写成的控制文件,用来在链接的整个过程中提供显式的、全局的控制。ld比其他链接器更有用的地方在于它提供了诊断信息。许多链接器在碰到错误的时候立即放弃执行,但ld却能够继续执行,让程序员发现其他的错误,或者在某些情况下,产生一个带有错误信息的输出文件。
如图《链接器的作用》所示说明了ld的工作内容。对于多源文件程序,每个源文件被汇编为目标文件(Object File),链接器负责把这些目标文件,以及相关的库文件链接到一起,形成可执行文件,这就是链接器的作用。
目标文件由若干段组成,包括代码段、数据段和未初始化数据段等。链接时,ld将打破目标文件由若干段组成,包括代码段、数据段和未初始化数据段等。链接时,ld将打破目标文件内部结构,把所有代码段都提取出来,共同组成最终可执行程序的代码段;把所有数据段提取出来,组成最终可执行程序的数据段;未初始化的数据段也做同样操作。