动态链接

由于静态链接会造成内存和磁盘空间的浪费,同时程序的更新存在问题。所以提出了动态链接的概念。具体来讲就是在程序真正运行的时候才进行链接操作,这个在一定成都上可能带来性能问题,不过这样增加了相同代码的共享,增加了内存的利用率。

动态链接的步骤:

1) 加载可执行文件(存在外部符号引用),过程与静态链接一样

2) 加载动态链接库ld.so

3)   操作系统将控制权交给动态链接器的入口地址

4) 动态连接器进行链接操作

5) 控制权交给可执行文件入口

在linux中常用的c语言库glibc,其动态链接形式的版本报讯在/lib目录下,最基本的libc.so。整个系统中只保留一份c语言的库,所有与c语言编写的,使用到动态链接的程序在执行中都要使用它。linux下的动态库文件(.so)只有到程序真正执行的时候才能确定具体的虚拟地址。

不过动态链接过程中的重定位问题却给我们带来了很大困扰。我们知道链接的一个非常重要的步骤就是重定位,其中包括符号的重定位和代码段中跳转,引用地址的重定位。在静态链接时,程序装载运行之前都已经链接完成,同时所有代码的虚拟地址也都已经确定。这样重定位的时候只需要确定相应引用位的虚拟地址就可以了。然而,在动态连接中程序的装载的时候是没有链接的,对于同一个共享库在不同程序中对应的虚拟地址可能不同,这样就造成代码段中的绝对地址引用不可使用,进而导致共享的失败。为了解决这个问题,可以将代码段中存在绝对地址引用的可变部分分离出来,放在数据段中。在进行共享的时候,代码段可以保持不变,而数据段对于每个进程都有一个副本。模块间的变量函数地址放在共享文件的GOT段中,存在于数据段中。

延迟绑定:在链接过程中,可能存在很多已经重定位的函数并没有被使用的情况,此时可以采用一种延迟绑定的策略,即在函数第一次被用到的时候才进行绑定。增加内存的利用率。


生成动态库文件也非常简单 gcc -shared -fPIC -o ***.so ***,c

其中 -shared表示生成共享库代码,-fPIC表示生成地址无关代码。


在共享库中的段与静态的.o文件略有不同,其中.interp段表示的是动态链接器的地址,一般为/lib/ld-linux.so.2, .dynamic段相当于静态链接器的头,其中存放的时各个段的信息。.dynsyn存放了与动态链接器相关的符号,不包括内部的符号。


自举代码:在讲述动态链接过程的时候我们提到使用动态链接器来进行动态链接工作,可是我们也应该注意到,动态链接器本身也是共享对象。它在执行之前也必须先进行虚拟地址的映射等。这个工作由谁完成呢?答案是自举代码。自举代码的作用就是完成动态链接器本身的重定位工作。这段代码中不能使用任何全局和静态变量,同时也不能使用函数,更不能依赖于其他的共享对象。

装载共享对象,完成自举后,将可执行文件与链接器本身的符号表合并在一起,称为全局符号表,然后递归查找依赖的共享对象,每个共享对象装载完成就更新全局符号表,当装载的对象存在多个同名的符号的时候,后边的符号会被前面的符号所覆盖。


显示运行时链接:对于共享库的调用我们也可以使用一些固定的API在运行时显示的加载共享库。这种方式使用灵活,也可以节约内存空间,其中dlopen用于打开共享库,dlerror英语判读错误,dlsym用于找到所需的符号 , dlclose用于将模块卸载。

共享库的系统路径:/lib 存放最关键的基础的共享库如:动态链接器,c运行库,数学库等主要是/bin和/sbin下的程序用的库。

/usr/lib 非系统所需的关键性的共享库

/usr/local/lib 存放和os并不十分相关的可 eg;/usr/bin/lib/python 其可执行文件存在与/usr/local/bin中


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值