当前位置:首页 > 科技  > 软件

动态链接库的实现原理是什么?

来源: 责编: 时间:2024-06-06 17:41:54 229观看
导读大家好,我是小风哥,今天简单聊聊动态链接库的实现原理。假设有这样两段代码,第一段代码定义了一个全量变量a以及函数foo,函数foo中引用了下一段代码中定义的全局变量b。图片第二段代码定义了全局变量b以及main函数,同时在m

大家好,我是小风哥,今天简单聊聊动态链接库的实现原理。buF28资讯网——每日最新资讯28at.com

假设有这样两段代码,第一段代码定义了一个全量变量a以及函数foo,函数foo中引用了下一段代码中定义的全局变量b。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

第二段代码定义了全局变量b以及main函数,同时在main函数中调用了第一个模块中定义的函数foo。buF28资讯网——每日最新资讯28at.com

接下来编译器出场,编译器会把这个两个源文件编译成对应的目标文件。buF28资讯网——每日最新资讯28at.com

目标文件中主要有两部分,代码段和数据段,这两部分里面分别包含什么内容呢?buF28资讯网——每日最新资讯28at.com

我们定义的全局变量会被放到数据段,代码被编译生成的二进制指令会被放到代码段,第二个目标文件也一样。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

注意看第一段代码,这里引用了一个其它模块定义的全局变量b,这一信息记录在第一个目标文件,第二段代码引用了其它模块定义的函数foo,这一信息记录在第二个目标文件。buF28资讯网——每日最新资讯28at.com

注意看第一段代码,这里定一个全局变量a和函数foo,我们记录下来,第二段代码定义了全局变量b和函数main,同样记录下来。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

接着我们开始一个叫做连连看的游戏。buF28资讯网——每日最新资讯28at.com

第一个模块引用了变量b,变量b的定义可以在第二个模块找到。buF28资讯网——每日最新资讯28at.com

第二个模块引用了函数foo,foo的定义可以在第一个模块找到。buF28资讯网——每日最新资讯28at.com

这个过程叫做符号解析。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

这里看到的引用以及定义的符号保存在所谓的符号表中。buF28资讯网——每日最新资讯28at.com

而如果第二个模块引用了一个叫做bar的变量,链接器翻遍所有其它模块都没找到bar这个符号的定义,而只找到了一个叫做foo的定义,这时链接器就会报一个叫做符合未定义的错误,这个错误写c/c++的程序员一定不陌生。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

接下来链接器会把数据段合并到一起,代码段合并到一起并确定符号的内存地址,这个过程叫做重定位。buF28资讯网——每日最新资讯28at.com

了解了这些就可以开始讲动态库的实现原理了,动态库又叫做共享库,我们的问题是,动态库是怎么实现可以被程序之间共享的呢?buF28资讯网——每日最新资讯28at.com

假设现在有两个运行的程序和一个动态库liba. so,动态库中定了一个全局变量a,第一个程序把变量a修改为了10。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

然后第二个程序开始运行,第二个程序也使用该动态库,然后把全局变量a修改为了20。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

这是第一个程序运行一段时间后决定打印变量a,这时你会惊讶的发现变量a从10变成了20,但是为什么。buF28资讯网——每日最新资讯28at.com

原因就是这两个程序共享了同一个数据段,所以一个程序对数据的修改对另一人程序是可见的,因此动态库中的数据段不能共享,每个程序需要有自己的数据段。buF28资讯网——每日最新资讯28at.com

现在数据的问题解决了,我们来看函数。buF28资讯网——每日最新资讯28at.com

假设动态库liba.so需要引用外部定义的foo函数,由于程序1和程序2都使用了该动态库,因此必须定义出foo函数。buF28资讯网——每日最新资讯28at.com

我们知道函数调用最终会被编译器翻译成call机器指令后跟函数地址。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

接下来我们需要解析出foo函数的地址到底是什么,这就是刚才我们提到的重定位,只不过动态库将这一过程推迟到了运行时。buF28资讯网——每日最新资讯28at.com

由于程序1的foo函数位于内存地址0x123这个位置,因此链接器将call指令后的地址修正为0x123。buF28资讯网——每日最新资讯28at.com

这时CPU执行这条call指令就能正确的跳转到第一个程序的foo函数。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

而第二个程序的foo函数为内存地址0x456这个位置,接下来第二个程序开始运行,CPU开始执行foo函数,由于第二个程序的foo函数在0x456,因此我们希望CPU能跳转到这里,但由于动态库中call指令后跟的是0x123这个内存地址,因此CPU执行foo函数时依然会跳转到第一个程序的foo函数。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

这时系统就出现了错误。buF28资讯网——每日最新资讯28at.com

问题出在了哪里呢?buF28资讯网——每日最新资讯28at.com

主要是call这条机器指令,这条指令后跟了一个绝对的内存地址,而不要忘了,这条指令或者说动态库是要被各个程序共享的,显然我们不能直接使用绝对地址。buF28资讯网——每日最新资讯28at.com

该怎么办呢?buF28资讯网——每日最新资讯28at.com

计算机中所有问题都可以通过增加一个中间层来解决。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

这样我们就摒弃了直接调用,而采用间接调用。buF28资讯网——每日最新资讯28at.com

而我们这里对函数的讨论对于全局变量的应用也是一样的道理,全局变量的使用也存在同样的问题,只不过是从函数调用变成了内存读写,解决问题的方法一样,我们从直接应用改为间接引用。buF28资讯网——每日最新资讯28at.com

接下来我们依然以函数调用为例来讲解。buF28资讯网——每日最新资讯28at.com

那么这个中间层到底是什么呢?buF28资讯网——每日最新资讯28at.com

答案就是got。buF28资讯网——每日最新资讯28at.com

还记得刚才提到的每个程序都有自己的数据区吗,这个got段就属于数据区的一部分。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

got中有什么呢?got中记录了引用的全局变量或者函数的地址,在程序运行时链接器会找到foo的内存地址,然后填到got表中,这样通过查got表我们就能知道函数foo的内存地址了。buF28资讯网——每日最新资讯28at.com

接下来的问题就是当CPU调用foo函数时怎么才能知道got表在哪里呢?buF28资讯网——每日最新资讯28at.com

注意刚提到每个程序都有自己的数据区,实际上对于动态库来说也有自己的代码区。buF28资讯网——每日最新资讯28at.com

我们现在只需要知道每个程序运行在自己的地址空间中,这些地址空间最终会被映射到真正的物理内存,动态库中的数据区会被映射到不同的内存区域,但代码段会被映射到同一段物理内存中,从而实现共享的目的。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

接下来我们重点看进程地址空间中的动态库布局。buF28资讯网——每日最新资讯28at.com

注意看,动态库的数据区和代码区总是相邻的,也就是代码区和got段的相对位置总是不变的,而不管动态库被放到了哪个位置。buF28资讯网——每日最新资讯28at.com

多个程序也一样,也就是代码区和数据区的相对位置总是固定的,这个相对位置在编译时编译器就能确定。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

现在foo会被编译成call指令,而程序在加载时链接器会向got段中写入foo的内存地址,显然两个程序的foo地址是不一样的。buF28资讯网——每日最新资讯28at.com

接下来CPU开始执行第一个程序的call指令,此时CPU会做一个相对跳转,这个跳转距离是编译器确定的,CPU会跳转到got表,然后查找foo的地址发现是0x123,然后开始执行0x123这个位置的函数。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

而如果CPU执行第二个程序中的foo函数,那么CPU同样会进行相对跳转,这不过这次跳转到的是第二个程序的got表,然后发现foo的地址是0x456,然后开始执行第二个程序中的foo函数。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

这样我们就实现了执行同一个指令但却会跳转到不同地址的目的,从而在不改动动态库代码的前提先实现共享。buF28资讯网——每日最新资讯28at.com

而如果一个动态库中引用了很多外部函数会怎么样呢?buF28资讯网——每日最新资讯28at.com

这样程序在启动时链接器不得不对所有函数进行重定位,因此会拖慢程序启动速度。buF28资讯网——每日最新资讯28at.com

而我们知道一个程序中不是所有的函数都会被调用到,经常调用的都是少数几个函数,为了利用这一点编译链接系统使用procedure linkage table, plt来推迟重定位这个过程,也就是程序在启动时不进行函数重定位,而是推迟到真正调用函数时,没用调用过的函数根本就不进行重定位,从而加快程序启动速度。buF28资讯网——每日最新资讯28at.com

从这个一过程我们可以看到动态库的这种间接调用实际上会对程序性能有一定影响,但相对于动态库带来的好处与便捷,这点影响可以忽略不计。buF28资讯网——每日最新资讯28at.com

这样,不管动态库被加载到内存的哪个位置都能正确被各个程序共享。buF28资讯网——每日最新资讯28at.com

动态库的这个特性被称之为位置无关代码,简称position-independent code, pic,这就是为什么你在编译生成动态库时要加上pic编译选项的原因。buF28资讯网——每日最新资讯28at.com

图片图片buF28资讯网——每日最新资讯28at.com

希望这篇对大家理解动态库有帮助。buF28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-92467-0.html动态链接库的实现原理是什么?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 为了全面监控用户行为,我写了个超级前端工具库!

下一篇: 三分钟带你秒懂CAS实现机制

标签:
  • 热门焦点
  • 一加Ace2 Pro官宣:普及16G内存 引领24G

    一加官方今天继续为本月发布的新机一加Ace2 Pro带来预热,公布了内存方面的信息。“淘汰 8GB ,12GB 起步,16GB 普及,24GB 引领,还有呢?#一加Ace2Pro#,2023 年 8 月,敬请期待。”同时
  • 红魔电竞平板评测:大屏幕硬实力

    前言:三年的疫情因为要上网课的原因激活了平板市场,如今网课的时代已经过去,大家的生活都恢复到了正轨,这也就意味着,真正考验平板电脑生存的环境来了。也就是面对着这种残酷的
  • 5月iOS设备好评榜:iPhone 14仅排第43?

    来到新的一月,安兔兔的各个榜单又重新汇总了数据,像安卓阵营的榜单都有着比较大的变动,不过iOS由于设备的更新换代并没有那么快,所以相对来说变化并不大,特别是iOS好评榜,老款设
  • JavaScript 混淆及反混淆代码工具

    介绍在我们开始学习反混淆之前,我们首先要了解一下代码混淆。如果不了解代码是如何混淆的,我们可能无法成功对代码进行反混淆,尤其是使用自定义混淆器对其进行混淆时。什么是混
  • 28个SpringBoot项目中常用注解,日常开发、求职面试不再懵圈

    前言在使用SpringBoot开发中或者在求职面试中都会使用到很多注解或者问到注解相关的知识。本文主要对一些常用的注解进行了总结,同时也会举出具体例子,供大家学习和参考。注解
  • 十个简单但很有用的Python装饰器

    装饰器(Decorators)是Python中一种强大而灵活的功能,用于修改或增强函数或类的行为。装饰器本质上是一个函数,它接受另一个函数或类作为参数,并返回一个新的函数或类。它们通常用
  • 东方甄选单飞:有些鸟注定是关不住的

    文/彭宽鸿编辑/罗卿东方甄选创始人俞敏洪带队的“7天甘肃行”直播活动已在近日顺利收官。成立后一年多时间里,东方甄选要脱离抖音自立门户的传闻不绝于耳,“7
  • 华为HarmonyOS 4.0将于8月4日发布 或搭载AI大模型技术

    华为宣布HarmonyOS4.0将于8月4日正式发布。此前,华为已经针对开发者公布了HarmonyOS4.0,以便于开发者提前进行适配,也因此被曝光出了一些新系统的特性
  • iQOO Neo8系列今日官宣:首发天玑9200+ 全球安卓最强芯!

    在昨日举行的的联发科新一代旗舰芯片天玑9200+的发布会上,iQOO官方也正式宣布,全新的iQOO Neo8系列新品将全球首发搭载这款当前性能最强大的移动平台
Top