Linux下动态链接的步骤与实现详解

1. 动态链接器的自举

我们知道动态链接器本身也是一个共享对象,但是事实上它有一些特殊性。对于普通共享对象文件来说,它的重定位工作由动态链接器来完成。他也可以依赖其他共享对象,其中的被依赖共享对象由动态链接器负责链接和装载。可是对于动态链接器来说,它的重定位工作由谁来完成?它是否可以依赖于其他共享对象?

这是一个“鸡生蛋,蛋生鸡”的问题,为了解决这种无休止的循环,动态链接器这个“鸡” 必须有些特殊性。首先是,动态链接器本身不可以依赖于其他任何共享对象;其次是动态链接器本身所需要的全局和静态变量和重定位工作由它本身完成。对于第一个条件我们可以认为的控制。在编写动态链接器时必须保证不使用任何系统库,运行库;对于第二个条件,动态链接器必须在启动时有一段非常精巧的代码可以完成这项艰巨的工作而同时又不能使用全局和静态变量。这种具有一定限制条件的启动代码往往被称为自举(Bootstrap)。

动态链接器入口地址即是自举代码的入口,当操作系统将进程控制权交给动态链接器时,动态链接器的自举代码即开始运行。自举代码首先会找到它自己的GOT。而GOT的第一个入口保存的是“.dynamic”段的偏移地址,由此找到了动态连机器本身的“.dynamic”段。通过“.dynamic”的信息,自举代码便可以获得动态链接器本身的重定位表和符号表等,从而得到动态链接器本身的重定位入口,先将它们全部重定位。从这一步开始,动态链接器代码中才可以使用自己的全局变量和静态变量。

实际上在动态链接器的自举代码中,除了不可以使用全局变量和静态变量之外,甚至不能调用函数,即动态链接器本身的函数也不能调用。这是为什么呢?其实我们在前面分析地址无关代码时已经提到过,实际上使用PIC模式编译的共享对象,对于模块内部的函数调用也是采用跟模块外部函数调用一样的方式,即使用 GOT/PLT的方式,所以在 GOT/PLT没有被重定位之前,自举代码不可以使用任何全局变量,也不可以调用函数。下面这段注释来自于 Glibc26.1源代码中的 elf/rtld.c

Linux下动态链接的步骤与实现详解

这段注释写在白举代码的末尾,表示自举代码已经执行结束。“ Now life is sane",可以想象动态链接器的作者在此时大舒一冂气,终于完成白举了,可以自由地调用各种函数并且随意访问全局变量了,

2. 装载共享对象

完成基本自举以后,动态链接器将可执行文件和链接器本身的符号表都合并到一个符号表当中,我们可以称它为全局符号表( Global Symbol Table)。然后链接器开始寻找可执文件所依赖的共享对象,我们前面提到过“.dynamic”段中,有一种类型的入口DT_NEEDED,它所指出的是该可执行文件(或共享对象)所依赖的共享对象。由此,链接器可以列出可执行文件所需要的所有共享对象,并将这些共享对象的名字放入到一个装载集合中。然后链接器开始从集合里取个所需要的共享对象的名字,找到相应的文件后打开该文件,读取相应的ELF文件头和“ .dynamic”段,然后将它相应的代码段和数据段映射到进程空间中。如果这个ELF共享对象还依赖于其他共享对象,那么将所依赖的共享对象的名字放到装载集合中。如此循环直到所有依赖的共享对象都被装载进来为止,当然链接器可以有不同的装载顺序,如果我们把依赖关系看作一个图的话,那么这个装载过程就是一个图的遍历过程,链接器可能会使用深度优先或者广度优先或者其他的顺序来遍历整个图,这取决于链接器,比较常见的算法一般都是广度优先的。

当一个新的共享对象被装载进来的时候,它的符号表会被合并到全局符号表中,所以当所有的共享对象都被装载进来的时候,全局符号表里面将包含进程中的所有动态链接所需要的符号。

符号的优先级

在动态链接器按照各个模块之间的依赖关系,对它们进行装载并且将它们的符号并入到全局符号表时,会不会有这么一种情况发生,那就是有可能不同的模块定义了同一个符号?让我们来看看这样一个例子:共有4个共享对象a1.so,a2.so, b1.so, b2.so,它们的源代码文件分别为a1.c, a2.c, b1.c 和 b2.c

/*a1.c*/ #include <stdio.h> void a1() { printf("a1.c\n"); } /*a2.c*/ #include <stdio.h> void a2() { printf("a2.c\n"); } /*b1.c*/ #include <stdio.h> void b1() { printf("b1.c\n"); } /*b2.c*/ #include <stdio.h> void b2() { printf("b2.c\n"); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d1529f1940a41c9a7205cdc6c4a42f1c.html