动态链接的执行过程

背景:静态链接库一旦链接进去,代码和变量的 section 都合并了,因而程序运行的时候,就不依赖于这个库是否存在。但是这样有一个缺点:

  • 就是相同的代码段,如果被多个程序使用的话,在内存里面就有多份

  • 而且一旦静态链接库更新了,如果二进制执行文件不重新编译, 也不随着更新

因而就出现了另一种,动态链接库(Shared Libraries),不仅仅是一组对象文件的简单归档,而是多个对象文件的重新组合,可被多个程序共享。

当一个动态链接库被链接到一个程序文件中的时候,最后的程序文件并不包括动态链接库中的代码,而仅仅包括对动态链接库的引用,并且不保存动态链接库的全路径,仅仅保存动态链接库的名称。当运行这个程序的时候,首先寻找动态链接库,然后加载它。

动态链接库,就是 ELF 的第三种类型,共享对象文件(Shared Object)(目标文件、可执行文件)

基于动态连接库创建出来的二进制文件格式还是 ELF,但是稍有不同。

  • 首先,多了一个.interp 的 Segment,这里面是 ld-linux.so,这是动态链接器,也就是说,运行时的链接动作都是它做的

  • 另外,ELF 文件中还多了两个 section,一个是.plt,过程链接表Procedure Linkage Table,PLT),一个是.got.plt,全局偏移量表Global Offset Table,GOT)。

它们是怎么工作的,使得程序运行的时候,可以将 so 文件动态链接到进程空间的呢?

dynamiccreateprocess 这个程序要调用 libdynamicprocess.so 里的 create_process 函数。由于是运行时才去找,编译的时候,压根不知道这个函数在哪里,所以就在 PLT 里面 建立一项 PLT[x]。这一项也是一些代码,有点像一个本地的代理,在二进制程序里面,不直接调用 create_process 函数,而是调用 PLT[x] 里面的代理代码,这个代理代码会在运行的时候找真正的 create_process 函数

去哪里找代理代码呢?这就用到了 GOT,这里面也会为 create_process 函数创建一项 GOT[y]。这一项是运行时 create_process 函数在内存中真正的地址。

如果这个地址在,dynamiccreateprocess 调用 PLT[x] 里面的代理代码,代理代码调用 GOT 表中对应项 GOT[y],调用的就是加载到内存中的 libdynamicprocess.so 里面的 create_process 函数了。

但是 GOT 怎么知道的呢?对于 create_process 函数,GOT 一开始就会创建一项 GOT[y],但是这里面没有真正的地址,因为它也不知道,但是它有办法,它又回调 PLT, 告诉它,你里面的代理代码来找我要 create_process 函数的真实地址,我不知道,你想想 办法吧。

PLT 这个时候会转而调用 PLT[0],也即第一项,PLT[0] 转而调用 GOT[2],这里面是 ldlinux.so 的入口函数这个函数会找到加载到内存中的 libdynamicprocess.so 里面的 create_process 函数的地址,然后把这个地址放在 GOT[y] 里面。下次,PLT[x] 的代理函 数就能够直接调用了。

posted @   小熊酱  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示