一.为什么要动态链接
二.装载时重定位
对于需要进行动态链接的共享对象,共享对象中的绝对地址在链接的时候不进行重定位,而是在装载运行的时候进行重定位。
由于需要动态链接的共享对象被装载映射至虚拟空间之后,指令部分是在多个进程之间共享的,由于装载时重定位的方法需要修改指令,所以没有办法做到同一份指令被多个进程共享,因为指令在被重定位之后对于每个进程来说是不同的。
三.地址无关代码(PIC)
上述装载时重定位的缺点是:指令部分无法在多个进程之间共享,这样就失去了动态链接节省内存的优势。为了解决这个问题,其实我们的目的很简单,希望共享对象中共享的指令部分在装载时不需要因为装载地址的改变而改变,所以实现的基本想法就是:把那些需要被修改的部分分离出来,跟数据部分放在一起,这样指令部分就可以保持不变,而数据部分在每个进程中都有一个副本,这种方法就叫做地址无关代码技术。
四.GOT和PLT
GOT是实现地址无关代码技术的方法。
PLT是加快动态链接的方法。
1)GOT
对于一个共享对象中的数据和函数,可以分成四类:
①模块内部的函数调用
②模块外部的函数调用
③模块内部的数据访问
④模块外部的数据访问
对于模块内部数据或者函数xxxxxx
对于模块外部数据或者函数的访问或调用,基本的思想就是将跟地址相关的部分放到数据段里面,这些其他模块中的函数或数据的地址跟模块的装载地址相关,ELF在数据段里面建立了一个指向这些变量的指针数组,这个指针数组就叫做GOT,如果想引用其他模块的函数或者数据,就通过GOT中相对应的项进行间接引用。
GOT是如何做到地址无关的呢?
2) PLT
动态链接相比于静态链接的优点和缺点:
优点:
缺点:
动态链接性能要比静态链接差一些,主要原因是以下两点:
①动态链接下对于其他模块的数据和函数的引用都要先进行GOT定位,然后再进行间接跳转。
②
为了加快动态链接:采用一种叫做延迟绑定的技术,基本的思想就是函数在第一次被用到的时候才进行绑定,包括符号查找,重定位等,然后将函数的真正地址填入到GOT表中。
用以实现延迟绑定的方法就是PLT。按照GOT的原理,当我们调用某个模块外部的函数或者数据时,我们通过GOT中相应的项进行间接的跳转,PLT为了实现延迟绑定,在这个过程中间又加了一层间接性。当我们调用某个模块外部的函数或者数据时,并不是直接通过GOT表进行跳转,而是通过一个叫做PLT项的结构进行跳转,每一个外部函数在PLT中都有一个项,例如我们在main函数中调用puts函数,puts函数在PLT