7.动态链接

7.1为什么要动态链接
慢慢静态模块的诸多缺点逐步暴露出来,比如浪费内存和磁盘空间、模块更新困难等问题,使得人们不得不寻找一种更好的方式来组织程序的模块。
内存和磁盘空间
当两个程序都用到某个模块,则在磁盘和内存中都会有两个副本。在静态链接中,C语言静态库是很典型的浪费空间的例子,还有其他数以千计的库如果都需要静态链接,那么空间浪费无法想象。
程序开发和发布
任何程序的小改动,都要重新链接,然后整个发给用户,那么通过网络来更新将会非常不便。
动态链接
把程序的模块相互分割开来,形成独立的文件,而不是将它们静态地链接在一起。简单地讲,就是不对那些组成程序的目标文件进行链接,等到程序要运行时才进行链接。也就是说,把链接这个过程推迟到了运行时再进行,这就是动态链接的基本思想。
加载至内存之后才链接的,如果要运行program2,那么系统不需要重新加载lib.o,因为内存中已经存在一份lib.o的副本,系统要做的只是将program2.o和lib.o链接起来。
内存中共享一个目标文件模块的好处不仅仅是节省内存,还可以减少物理页面的换入换出,也可以增加CPU缓存的命中率,因为不同进程间的数据和指令访问都集中在了同一个共享模块上。
甚至可以使用不同的语言,动态链接使得开发过程中各个模块更加独立,耦合度更小,便于不同开发者和开发组织之间独立进行开发和测试。
程序可扩展性和兼容性
动态链接库可增加插件的功能;相当于在程序和操作系统间增加了一个中间层,从而消除了程序对不同平台之间依赖的差异性。
问题:缺少有效的共享库版本管理机制,让新旧接口不兼容,导致原有程序无法运行。
动态链接的基本实现
当程序被装载的时候,系统的动态链接器会将程序所需要的所有动态链接库装载到进程的地址空间,并且将程序中所有未决议的符号绑定到相应的动态链接库中,并进行重定位工作。
动态链接是把连链接从本来的程序装载前被推迟到了装载的时候。
7.2简单的动态链接例子
这里写图片描述
这里写图片描述
动态链接程序运行时的地址空间分布
这里写图片描述
readelf看到,so文件的转载地址是0,即地址分配不是固定的。
7.3地址无关代码
7.3.1固定装载地址的困扰
为了解决模块装载地址固定的问题:共享对象在编译时不假设自己在进程虚拟地址空间中的位置。与此不同的是,可执行文件基本可以确定自己在进程虚拟空间中的起始位置,因为可执行文件往往是第一个被加载的文件,它可以选择一个固定空闲的地址,比如Linux下一般都是0x08040000,windows下一般都是0x00400000。
7.3.2装载时重定位
程序被直接装载到物理内存时,是一个整体,程序中指令和数据的相对位置是不会改变的。比如编译时假设装载地址为0x1000,但是实际装载至了0x4000,程序指令或数据中的所有绝对引用都加上0x3000就可以了。
我们前面在静态链接时提到过重定位,那时的重定位叫做链接时重定位,而现在这种称为装载时重定位。
但是装载时重定位的方法不适合解决上面的共享对象中所存在的问题。可以想象,动态链接模块被装载映射至虚拟空间后,指令部分是在多个进程间共享的,由于装载时重定位的方法需要修改指令(+0x3000?!),所以没有办法做到一份指令被多个进程共享,因为指令被重定位后对于每个进程来讲是不同的。
7.3.3 地址无关代码
我们的目的很简单,希望程序模块中共享的指令部分在装载时不需要因为装载地址的改变而改变,所以实现的基本方法是把指令中那些需要被修改的部分分离出来,跟数据部分放在一起,这样指令部分就可以保持不变,而数据部分可以在每个进程中拥有一个副本。这种方法就是目前被称为地址无关代码(PIC)的技术。
类型一 模块内部调用或跳转
类型二 模块内部数据访问
类型三 模块间数据访问
类型四 模块间调用、跳转
地址无关代码小结
这里写图片描述
这里写图片描述
7.5动态符号表
ELF专门有一个叫做动态符号表的表示动态链接这些模块之间的符号导入和导出关系。段名通常叫做“.dynsym”。(在so文件中,每个函数的结构描述是存放在.dynsym段中的。每个函数的名称保存在.dynstr段中的)dynsym只保存了与动态链接相关的符号,对于那些模块内部的符号,比如模块私有变量则不保存。很多时候symtab中往往保存所有符号,包括dynsym中的符号。
与symtab类似,dynsym也需要辅助表,比如用于保存符号名的字符串表,静态链接时叫做符号字符串表“strtab”,在这里就是动态符号字符串表“dynstr”。由于动态链接在程序运行时查找符号,为了加快符号的查找过程,往往还有辅助的符号哈希表。
7.5.4动态链接重定位表
7.7显示运行时链接
dlopen()函数打开动态库,执行init返回句柄
dlsym()函数找到所需要的符号
dlclose(),执行finit,然后卸载动态库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值