动态链接与位置无关代码



  • 动态链接与位置无关代码

    在代码编写到运行过程中,符号地址的确定可以在编译链接时确定,这种技术对应静态链接,而大部分静态语言之所以叫做静态也是因为变量地址在编译时就已经确定了。

    当然符号地址也可以在装载(load)时确定,动态链接就用到了这种技术。

    当然还可以完全在运行的时候确定符号或变量的位置,动态语言比如Python之类就是在运行的时候动态查找变量,这是动态语言的一大核心(貌似扯远了)。

    静态链接

    在多个目标文件链接成一个可执行文件时,可执行文件完全持有每一个文件的代码和数据,即相当于保留了每一个目标文件的副本,这样在链接时可以对每个目标文件中的符号进行重定位,使之合并成一个可执行文件。
    并且所有的文件必须共同链接,不然就无法确定某一个符号或者代码的地址。

    但是静态链接存在一个很大的问题,就是空间的浪费。由于可执行文件保留每一个目标文件的副本,这使得很多程序包含很多公用的代码,比如几乎每个IO程序可能都包含了printf,scanf之类的常用代码,这使得代码冗余,空间浪费。

    静态链接还存在一个很严重的问题,一个小的目标文件如果有修改,需要重新链接整个项目,这样效率是缓慢的。

    当然这样也有好处,每一个可执行文件都持有副本,就可以对自己的副本进行任意操作不用担心影响其他程序,比如重定位。

    动态链接

    而动态链接技术消除了空间浪费问题(其实也有一点,你想数据段无论如何也是不能共享的吧,除非是只读的)和对于链接的目标文件的静态依赖,通过把重定位转移到了装载和运行时。有得必有失,这样动态链接必然比静态链接装载执行慢一些。

    由于动态链接的通过动态共享一份目标代码,解决了空间浪费和重新链接问题。不同进程之间的共享可以通过地址映射解决。我们现在有两个选择:

    • 为每个动态链接库规定一个固定的地址,这样减小了动态链接库编译的难度,因为在编译期链接库就知道自己需要装载的地址,跟普通的编译没有什么区别。但是这样我们必须为每一个链接库保留地址空间,即使可能我们没有用到它,进一步链接库的更新对于这个保留地址管理都是一个挑战,而且保留地址完全移除了虚拟地址做出的努力。
    • 使得动态链接库的代码可以在任意位置执行,显然采取这种方式更加灵活,且动态链接库中必然不能有绝对地址,与之相伴的技术PIC(position independence code)可以用来解决这个问题。

    PIC

    要做到位置无关代码,必然要求每一个链接这个动态共享库的可执行程序对于同一个符号的引用可以是不同的。而由于是共享的,每个动态链接库代码段的内容是完全一样的,这样只能在数据段做手脚了,这样对应了上文中我们提到的不同程序的对于链接库的数据段是不共享的。

    位置无关代码在数据段开始为每一个全局符号保留了一个条目(GOT global offset table),每一个条目中保存了全局符号的绝对地址(这个绝对地址,在动态链接库装载的时候被填写),每次对动态链接中全局符号的引用,首先找到GOT中的条目,然后获得全局符号的地址,这样就实现了位置无关代码。

    现在我们从头梳理一下和动态链接库中链接时的所有流程和已知条件:

    1. 发现任何引用动态链接库中的符号 - 在链接时动态链接器可以发现
    2. 修改符号引用代码(具体如上),使得其代码无关。(每个引用全局符号的模块都有其GOT,GOT的绝对位置在链接时便可以确定,相当于静态链接。)
    3. 主程序与动态链接库装入内存,开始执行。

    (这里缺少了一部分动态链接程序对于外部符号的引用,与主程序引用动态链接符号同理,不再赘述。)

    PIC补充

    如上一节,你可以看到,对于每一个符号引用需要多一次寻址过程(GOT中表查找)和几条代码的运算,可以说降低了一点性能。其实PIC对于全局变量和全局函数的处理稍有不同。

    全局函数还使用了PLT(procedure linkage table)和延迟绑定(lazy binding)技术,减少了一定的额外代码数量,通过将函数定制的绑定推迟到第一次函数执行的时候。(个人感觉没什么意思,有兴趣的请自行查阅。)

    总结

    为了解决单个文件过大和编译困难的问题,我们发明了多文件之间编译链接技术,从而使一个文件的变化不用整个项目进行编译。更进一步通过动态链接技术,一个文件的变化,整个项目的重新链接也不需要了。

    (这一点和动态语言的发展是多么相似,动态类型的引入使得代码之间的耦合度降低,符号动态查找使程序更加自由灵活具有动态性。【存疑】)当然将过多的任务引入到运行期可能会带来效率上的下降,但是它的好处也是那么显而易见,不是么?

    欢迎拍砖。


  • Blogspace Alpha

    动态链接还有一个弊端,就是版本管理变得复杂



  • 让我想起了java中的动态绑定(后期绑定)和静态绑定(前期绑定)


Log in to reply