静态库的问题
- 空间浪费。
- 对程序的更新、部署和发布会带啦很多麻烦。如果某一个模块更新,则需要重新链接所有的文件。
为了解决这两个问题,把程序的模块分隔开来形成独立文件,把链接这一过程推迟到运行时在进行——动态链接的基本思想。
动态链接的基本思想
动态链接的基本思想:把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接那样把所有的程序模块都链接成一个单独的可执行文件。
在使用动态链接库的情况下,程序本身被分为程序主要模块(Program1)和动态链接库(Lib.so)。
动态链接基本分为3步:动态链接器自举、装载共享对象、重定位和初始化。
动态链接器本身是静态链接的,是PIC的。
地址无关代码
装载时重定位:在链接时,对所有绝对地址的引用不做重定位,而把这一步推迟到装载时在完成。一旦模块装载地址确定,即目标地址确定,那么系统就对程序中所有的绝对地址进行重定位。
静态链接的重定位,称为链接时重定位;共享库的重定位,称为装载时重定位。
地址无关代码技术:把指令中那些需要被修改的部分分离出来,跟数据部分放在一起,这样指令部分就可以保持不变,而数据部分可以在每个进程中拥有一个副本。如果不是地址无关的就不可以被多个进程共享。
模块中的各种类型的地址引用方式:
1. 模块内部调用或跳转(无需重定位)
2. 模块内部数据访问(相对寻址)
3. 模块间数据访问(在数据段里面建立一个指向这些变量的指针数据,称为全局变量表GOT)
4. 模块间调用、跳转(通过GOT中保存的目标函数的地址进行间接跳转)
延迟绑定
函数第一次被用到时才进行绑定(符号查找、重定位等),如果没有用到则不进行绑定。所以程序执行时,模块间的函数调用都没有进行绑定,而是需要用到时才由动态连接器负责绑定。