技术专题

链接器和加载器原理

2009年5月8日 阅读(16)

关于链接器和加载器。主要完成重定位和符号解析。它的存在使得多文件编译称为可能,使得项目可以分割到多个文件,避免了将所以程序写到一个大文件里,一次编译。可以分别编译,然后用链接器链接起来。

看一个编译器产生的目标文件后,生成的目标文件中,包括data段,text段,bss段,同时为了链接还有重定位表,符号表,如果要支持调试还有调试信息。

其中bss段保存了那些未初始化的数据,分配空间时初始为0。重定位表,则包含了重定位需要的信息,比如包括程序段内那些需要重定位的位置,比如变量地址,转移地址,这些与基地址有关的东西,在基地址改变时需要修改的位置,比如初始它们假设以0为基地址,现在链接器把段合并,其中某些目标文件相应的基地址必然发生改变,那么链接器就要根据这个表找到这些位置对它们按照新的基地址进行更新。符号表,则保存了一些全局变量的定义及用到的地方,比如一些已定义的,或者未定义的外部符号。

调试信息,则可能包括目标代码与源代码行之间的对应关系,这样才能在调试时使图形界面对应到正确的源代码行,或者发生错误时正确找到对应的源代码行。

重定位表和符号表,是最重要的两个表,主要完成重定位和符号解析。对于一个单独目标文件来说,也经常需要链接,因为程序通常需要系统库的支持,比如基本io库,这样就需要连接器去库路径里搜索到需要的模块,将其链接到当前的目标文件中。注意这里的符号表,是主要用来让链接器和加载器在合并文件,查找外部引用,重定位的时候使用的,与编译阶段的符号表具有类似的作用,但它们不是同一个,编译的符号表是词法分析后,用来为后面的编译服务的。

有的目标文件,在链接时就确定了地址,这样程序加载时就可以直接加载到那个地址,这叫静态链接。但有时候需要动态链接,这样就需要保存重定位信息和符号表信息,在运行时重定位,由加载程序在根据加载时确定的基地址对程序做一次处理。

考虑一个c++程序的例子:a.cpp b.cpp main.cpp

首先编译生成独立的目标文件a.o,b.o.main.o它们含有data text bss等段,同时生成了重定位表 符号表

然后链接,需要把它们中各自的data,text,bss,init等段,聚合在一块,让data段在一块,text段在一块,原来的目标文件可能假设基地址是0,但经过这个合并,其中一些模块的基地址就要发生改变,就需要完成重定位,比如要修改模块中某些地址的值,这时就需要根据重定位表对这些需要修改的位置进行修改。

同时这时要解决各个模块之间的相互引用,就需要符号表,符号表包括了当前模块中定义的全局符号,被引用但未被定义的符号,段名称,通过这些名称,确定那些引用,同时确定那些引用需要去库中链接,把已知的符号用它们的真实地址或者值代替。

对于c++,链接器可能还要收集各个模块中的初始化和析构代码,将他们组织到一块。

 转载请注明作者:phylips@bmy 出处:http://duanple.blog.163.com/blog/static/7097176720094874045208/

You Might Also Like

No Comments

Leave a Reply