设为首页 加入收藏

TOP

动态链接的相关结构(一)
2019-04-02 22:08:50 】 浏览:202
Tags:动态 链接 相关 结构

在了解了共享对象的绝对地址的引用问题后,我们基本上对动态链接的原理有了初步的了解,接下来的问题是整个动态链接具体的实现过程了。动态链接在不同的系统上有不同的实现方式。ELF的动态链接的实现方式会比PE的简单一点,在这里我们先介绍ELF的动态链接过程在LINUX下的实现,最后我们会专门的章节中介绍PE在Windows下的动态链接过程和它们的区别


我们在前面的章节已经看到,动态链接情况下,可执行文件的装载与静态链接情况基本样。首先操作系统会读取可执行文件的头部检查文件的合法性,然后从头部中的“ Program Header”中读取每个“Segment”的虚拟地址、文件地址和属性,并将它们映射到进程虚拟空间的相应位置,这些步骤跟前面的静态链接情况下的装载基本无异。在静态链接情况下,操作系统接着就可以把控制权转交给可执行文件的入口地址,然后程序开始执行,一切看起来非常直观。


但是在动态链接情况下,操作系统还不能在装载完可执行文件之后就把控制权交给可执行文件,因为我们知道可执行文件依赖于很多共享对象。这时候,可执行文件里对于很多外部符号的引用还处于无效地址的状态,即还没有跟相应的共享对象中的实际位置链接起来。所以在映射完可执行文件之后,操作系统会先启动个动态链接器( Dynamic Linker)


在 Linux下,动态链接器ld.so实际上是一个共享对象,操作系统同样通过映射的方式将它加载到进程的地址空间中。操作系统在加载完动态链接器之后,就将控制权交给动态链接器的入口地址(与可执行文件一样,共享对象也有入口地址)。当动态链接器得到控制权之后,它开始执行一系列自身的初始化操作,然后根据当前的环境参数,开始对可执行文件进行动态链接工作。当所有动态链接工作完成以后,动态链接器会将控制权转交到可执行文件的入口地址,程序开始正式执行。


那么系统中哪个才是动态链接器呢,它的位置由谁决定?是不是所有的*NX系统的动态链接器都位于 /lib/ld.so呢?实际上,动态链接器的位置既不是由系统配置指定,也不是由环境参数决定,而是由ELF可执行文件决定。在动态链接的ELF可执行文件中,有一个专门的段叫做“ Interp”段(“ Interp”是“ Interpreter”(解释器)的缩写)。如果我们使用 objdump工具来查看,可以看到“ .interp”内容:



".interp"的内容很简单,里面保存的就是一个字符串,这个字符串就是可执行的所需要的动态链接器的路径。在LINUX下,可执行文件所需要的动态链接器的路径几乎都是 “/lib/ld-linux.so.2”,其他的*.nix操作系统可能会有不同路径。我们在后面还会介绍到各种环境下的动态链接器的路径。在LINUX系统中,/lib/ld-linux.so.2通常是一个软链接,比如在我的机器中,它指向/lib/ld-linux.so.2,这个才是真正的动态链接器,在linux中,操作系统在对可执行文件所需要的相应动态连接器,即“.interp”段指定的路径的共享对象;


动态链接器在linux下是glibc的一部分,也就是属于系统库级别的,它的版本号往往跟系统的Glibc库版本号是一样的,比如我的系统中安装的是glibc 2.6.1,那么相应的动态链接库就是/lib/ld-2.6.1.so。当系统中的Glibc库更新或者安装其他版本的时候,/lib/ld-linux.so.2 这个软链接就会指向新的动态链接器,而可执行文件本身不需要修改 ".interp" 中的动态链接器路径来适应系统的升级


我们往往可以用这个命令来查看一个可执行文件所需要的动态链接器的路径,在linux下,往往是这个结果:


而当我们在FreeBSD 4.6.2 下执行这个命令时,结果是:


64 位的linux下的可执行文件是:


类似于“.interp”这样的段,ELF中还有几个段也是专门用于动态链接的,比如 ".dynamic" 段和 ".dynsym"段等。要了解动态链接器如何完成链接过程,跟前面一样,从了解ELF文件中跟动态链接相关的结构入手将会是一个很好的途径。ELF文件中跟动态链接相关的段有好几个,相互之间的关系也比较复杂,我们先从 ".dynamic" 段入手


动态链接ELF中最重要的结构应该是“ .dynamic”段,这个段里面保存了动态链接器所需要的基本信息,比如依赖于哪些共享对象、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等。“ .dynamic”段的结构很经典,就是我们已经碰到过的ELF中眼熟的结构数组,结构定义在“elf.h”中:


Elf32_Dyn 结构由一个类型值加上一个附加的数值或指针,对于不同类型,后面附加的数值或者指针有着不同含义。我们这里列举几个比较常见的类型值(这些值都是定义在“elf.h”里面的宏),如表7-2所示:



表7-2中只列出了一部分定义,还有一些不太常用的定义我们就暂且忽略,具体可以参考LSB手册和elf.h的定义。从上面给出的定义来看,“.dynamic”段里面保存的信息有点像elf文件头,只是我们看到的elf文件头中保存的是静态链接时的相关信息,比如静态链接时使用到的符号表、重定位表等,这里换成了动态链接下所使用的相应信息了。所以,“.dynamic”段可以看成动态链接下的ELF文件的“文件头”。使用readelf工具可以查看 ".dynamic" 段的内容




另外Linux还提供了一个命令用来查看一个程序主模块或一个共享库依赖于哪些共享库:



为了完成动态链接,最关键的还是所依赖的符号和相关文件的信息。我们知道在静态链接中,有一个专门的段叫做符号表“.symtab”( Symbol Table),里面保存了所有关于该目标文件的符号的定义和引用。动态链接的符号表示实际上它跟静态链接十分相似,比如前面例子中的 Program1程序依赖于 Lib.so,引用到了里面的 foobar()函数。那么对于 Program1来说,我们往往称 ProgramI导入( Import)了 foobar函数, foobar是 Program1的导入函数(import Function):而站在Lib.so的角度来看,它实际上定义了 foobar函数,并且提供给其他模块使用,我们往往称Lib.so导出( Export)了 foobar函数, foobar是Lbso的导出函数(Export Function)。把这种导入导出关系放到静态链接的情形下,我们可以把它们看作普通的函数定义和引用。


为了表示动态链接这些模块之间的符号导入导出关系,ELF专门有一个叫做动态符号表(Dynamic symbol table)的段用来保存这些信息,这个段的段名通常叫做“.dynsym”(Dynamic Symbol)。与 “.sysmtab”不同的是,".dynsym" 只保存了与动态链接相关的符号,对于那些模块内部的符号,比如模块私有变量则不保存。很多时候动态链接的模块同时拥有“.dynsym” 和 ".sysmtab"中往往保存了所有符号,包括 “.dynsym” 中的符号


与 “.sysmtab” 类似, 动态符号表也需要一些辅助的表,比如用

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Linux下动态链接的步骤与实现详解 下一篇Linux动态链接过程延迟绑定的实现

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目