编译链接中的-可重定位目标文件

来源:互联网 发布:js attr style 编辑:程序博客网 时间:2024/06/06 13:00

可重定位目标文件理解

资料一:

汇编器所产生的目标文件至少包括三个区,即文本区(text),数据区(data)和bss区。文本区一般包括程序的代码和常量,数据区通常存放全局变量等内容,bss区用于存放未初始化的变量或作为公共变量存储空间。在一个目标文件中,其text区从地址0开始,随后是data区,再后面是bss区。而要运行程序,必须装载到内存中,所以这些区的地址需要在内存中重新安排,也就是重定位。

资料二:

编译器编译后产生的目标文件是可重定位的程序模块,并不能直接运行,链接就是把目标文件和其他分别进行编译生成的程序模块(如果有的话)及系统提供的标准库函数连接在一起,生成可运行的可执行文件的过程。
重定位是链接器在完成符号解析后(知道了各个输入模块的代码段和数据段的大小)的一个步骤,其作用顾名思义就是重新定位,确定比如指令,全局变量等在运行时的存储器地址。       

资料三:

比如说两个编译后的可重定位目标文件obj1.o和obj2.o
在obj1.o里面定义了一个全局变量glob(在obj1里面记录了glob相对于该文件数据段的相对地址), 而obj2.0里面又引用了这个全局变量glob。
链接的重定位就是要确定在链接后的可执行程序中glob的地址,而不是相对于obj1的地址,从而使obj2也能通过地址调用glob。

当然重定位并不只是全局变量,还包括外部函数,指令等运行时地址的确定

资料四:

当你在程序中写上一个全局变量或者是一个函数时,这个定位过程会经历几个阶段:
1.在这个目标文件中的相对定位,一个目标文件中会此文件中的所有函数,变量进行符号描述,比如一个变量A,它所占的相对地址是多少?是全局的?或者是静态的,或者是外部的??
2.在连接多个目标成一个可执行文件时,会再次对这个变量进行重定位,也就是在这个可执行文件中进行对此变量进行描述,同目标文件中的描述差不多,只不过此变量不再有外部,内部之分,都成了本地变量,并且会将所有全局变量存放在一定的逻辑地址中,这是通过连接脚本文件与各个目标文件中的相对地址共同决定的
3.最终的操作系统加载这个可执行文件时,会对这些变量与函数地址再次进行重定位,其方式就是首先分析这个可执行文件中的不同段,读出相应的描述表,然后通过逻辑地址与物理地址进行映射出,最终就将可执行的二进制码加进了真实的物理内存了,关于分析可执行文件格式与物理地址的转换,不同的CPU与操作系统的实现方式会有不同之处

综上一些资料,自己有了一个大概的理解,毕竟没学过编译原理这方面,只能有个感性的认识,

编译器把代码文件编译处理为一个可执行的二进制文件,在window上后缀为exe的可执行文件,linux上生成的可执行文件没有后缀来标示,

比如,从一个c源代码文件变成一个可执行文件,这期间编译器做了很多事情

这些事情依次是:预处理(宏展开等),编译(将c代码翻译成为汇编指令),汇编(将汇编代码翻译成机器指令,也叫可重定位目标文件),

链接(链接由汇编产生的目标文件)。关于这几个事情具体详细的起到了什么作用,可参阅博主其他文章或谷歌一下,你全知道!

经过汇编后的目标文件可以被链接成为二进制可执行文件。主题来了,链接做了什么?

请看上面的资料三,把多个文件链接成为一个文件,之前的各个文件中的 符号,变量在内存中的地址是相对的,

链接过程中会把多个文件的相同类型数据段代码段放在一起,所以需要将里面的符号变量重新安置在一个确定的内存地址中,这就是重定位,



重定位目标文件,链接

源文件被编译汇编成可重定位目标文件,文件包含数据区,代码区,符号表等。符号表表示源文件中变量和函数在各自区中的位置,所占大小等信息。目标文件中的符号可引用其他可重定位目标文件中的符号,在连接器解析符号的时候对这些符号进行联系。

    目标文件也可以叫做模块,由函数和变量集合组成。
    静态链接库里由很多模块组成,且每个模块只有一个函数组成。一个模块调用静态链接库,不会把链接库里的所有模块都链接起来,只会链接用到的目标模块,减少了最终可执行文件的内存大小。
    符号解析过程:解析每个输入模块,把未定义的符号放入U,定义的符号放入D,如果输入模块中的符号是定义U中的符号,则把该符号放入D。最后U为空则链接成功。
    静态链接库是把库的函数载入嵌套在最后的可执行文件中,而动态链接库是在源程序中调用动态链接函数dlope,dlsym,dlclos,该函数来获得动态链接库里用到的函数指针。

0 0