动态链接:共享程序
Posted rxmind
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态链接:共享程序相关的知识,希望对你有一定的参考价值。
前言:
前面讲过,通过链接将不同文件内的代码合并到一起成为一个可执行文件,才能加载运行,在不同程序链接的过程中,有些代码是被多次复用的,如果每个程序装载的时候都去重复装载这部分代码,就会使这些相同的代码重复占用内存。
(一)链接分动静,共享省内存
要解决这个问题,我们希望不同程序引用相同代码时,都只需装载一次,这就是动态链接;而之前直接合并代码的方式称之为静态链接。动态链接中,链接的是加载到内存中的共享库,在Windows里是.dll文件,在Linux下是.so文件。
二、要想“地址无关”,使用“相对地址”
想要在程序运行时共享代码,那么这些机器码必须是地址无关的。对于所有动态链接共享的程序来说,即使共享库用的是同一段物理内存地址,但在不同的应用程序里其虚拟内存地址也是不同的。动态库编译出的代码指令通过如下方式做到地址无关:
- 动态代码库中的变量和函数通过相对地址保证其地址性
- 指令中使用的内存地址给出的也不是绝对地址而是一个相对当前指令偏移量的内存地址,因为整个共享库存储在一段连续的虚拟内存地址,无论被装载到哪个程序,他们之间的相对地址不会改变。
三、PLT和GOT,动态链接的解决方案
编译完成的地址无关的代码文件中,对于共享库函数的调用需要从PLT也就是程序链接表中找到调用的函数。
在共享库的data section中保存了一张全局偏移表GTO,虽然共享库的代码部分物理地址共享,但数据部分是各个动态链接它的应用程序各自加载一份。所有需要引用当前共享库外部地址的指令都会查询GOT,来找到当前运行程序的虚拟内存里的对应位置。
而GOT里的数据,则是在加载一个个共享库时写入的。因此调用同样动态库的不同应用程序各自GOT中最终加载的动态链接库中的虚拟内存地址是不同的。
这样只要各个应用程序维护好自己的GOT就可以共享动态库中的代码,而不需要修改动态库中代码所使用的的地址。
共享库代码部分直接使用,外部变量和函数部分通过各自GOT来计算得到。
总结:
通过使用动态链接,使得代码不仅在编码过程完成了服用,在运行阶段也做到了复用,这一点颇类似于jvm的类装载机制,统一将各个类装载进jvm后再调用,难怪被称为虚拟机,并且jvm是类被使用时才加载,这就更加灵活而且还加快了启动速度、节省了内存空间。
以上是关于动态链接:共享程序的主要内容,如果未能解决你的问题,请参考以下文章
linux ldconfig命令的作用(Linker Configuration 链接器配置)更新动态链接库(共享库)的链接器程序缓存