重学计算机组成原理(九)- 动态链接(下)

简介: 重学计算机组成原理(九)- 动态链接(下)

3 动态链接的解决方案

PLT和GOT

要实现动态链接共享库,也并不困难,和前面的静态链接里的符号表和重定向表类似

拿出一小段代码来看一看。

lib.h

定义了动态链接库的一个函数 show_me_the_money

image.png

lib.c

包含了lib.h的实际实现

image.png

show_me_poor.c

调用了 lib 里面的函数

image.png

把 lib.c 编译成了一个动态链接库,也就是 .so 文件

image.png

最终生成文件集

image.png

在编译的过程中,指定了一个 -fPIC 的参数

其实就是Position Independent Code意,也就是要把这个编译成一个地址无关代码

然后,我们再通过gcc编译 show_me_poor 动态链接了 lib.so 的可执行文件


在这些操作都完成了之后,我们把 show_me_poor 这个文件通过objdump出来看一下。

image.png

0000000000400540 <show_me_the_money@plt-0x10>:
  400540:       ff 35 12 05 20 00       push   QWORD PTR [rip+0x200512]        # 600a58 <_GLOBAL_OFFSET_TABLE_+0x8>
  400546:       ff 25 14 05 20 00       jmp    QWORD PTR [rip+0x200514]        # 600a60 <_GLOBAL_OFFSET_TABLE_+0x10>
  40054c:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]
0000000000400550 <show_me_the_money@plt>:
  400550:       ff 25 12 05 20 00       jmp    QWORD PTR [rip+0x200512]        # 600a68 <_GLOBAL_OFFSET_TABLE_+0x18>
  400556:       68 00 00 00 00          push   0x0
  40055b:       e9 e0 ff ff ff          jmp    400540 <_init+0x28>
……
0000000000400676 <main>:
  400676:       55                      push   rbp
  400677:       48 89 e5                mov    rbp,rsp
  40067a:       48 83 ec 10             sub    rsp,0x10
  40067e:       c7 45 fc 05 00 00 00    mov    DWORD PTR [rbp-0x4],0x5
  400685:       8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  400688:       89 c7                   mov    edi,eax
  40068a:       e8 c1 fe ff ff          call   400550 <show_me_the_money@plt>
  40068f:       c9                      leave  
  400690:       c3                      ret    
  400691:       66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  400698:       00 00 00 
  40069b:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

我们还是只关心整个可执行文件中的一小部分内容

  • 在main函数调用show_me_the_money的函数的时候,对应的代码是这样的:

image.png

这里后面有一个@plt的关键字,代表了我们需要从PLT,也就是程序链接表(Procedure Link Table)里面找要调用的函数。对应的地址呢,则是400580这个地址。


那当我们把目光挪到上面的 400580 这个地址,你又会看到里面进行了一次跳转,


这个跳转指定的跳转地址,你可以在后面的注释里面可以看到:


image.png

image.png

这里的 GLOBAL_OFFSET_TABLE,就是我接下来要说的全局偏移表。

在动态链接对应的共享库,我们在共享库的data section里面,保存了一张全局偏移表(GOT,Global Offset Table)

虽然共享库的代码部分的物理内存是共享的,但是数据部分是各个动态链接它的应用程序里面各加载一份的。

所有需要引用当前共享库外部的地址的指令,都会查询GOT,来找到当前运行程序的虚拟内存里的对应位置

而GOT表里的数据,则是在我们加载一个个共享库的时候写进去的。


不同的进程,调用同样的 lib.so,各自GOT里面指向最终加载的动态链接库里面的虚拟内存地址是不同的。


这样,虽然不同的程序调用的同样的动态库,各自的内存地址是独立的,调用的又都是同一个动态库,但是不需要去修改动态库里面的代码所使用的地址,

而是各个程序各自维护好自己的GOT,能够找到对应的动态库就好了


image.png

image.png

GOT表位于共享库自己的数据段里

GOT表在内存里和对应的代码段位置之间的偏移量,始终是确定的

这样,共享库就是地址无关的代码,对应的各个程序只需在物理内存里加载同一份代码

而我们又要通过各个可执行程序在加载时,生成的各不相同的GOT表,找到它需要调用到的外部变量和函数的地址


这是一个典型的、不修改代码,而是通过修改“地址数据”来进行关联的办法


它有点像我们在C语言里面用函数指针来调用对应的函数,并不是通过预先已经确定好的函数名称来调用,而是利用当时它在内存里面的动态地址来调用。


4 总结

终于在静态链接和程序装载后,利用动态链接把我们的内存利用到了极致

同样功能的代码生成的共享库,我们只要在内存里面保留一份就好了

这样

  • 不仅能够做到代码在开发阶段的复用
  • 也能做到代码在运行阶段的复用。


实际上,在进行Linux程序开发,一直会用到各种各样的动态链接库。

C语言的标准库就在1MB以上。

撰写任何一个程序可能都需要用到这个库,常见的Linux服务器里,/usr/bin下面就有上千个可执行文件。

如果每一个都把标准库静态链接进来的,几GB乃至几十GB的磁盘空间一下子就用出去了。如果我们服务端的多进程应用要开上千个进程,几GB的内存空间也会一下子就用出去了。这个问题在过去计算机的内存较少的时候更加显著。


通过动态链接这个方式,可以说彻底解决了这个问题。

就像共享单车一样,如果仔细经营,是一个很有社会价值的事情,但是如果粗暴地把它变成无限制地复制生产,给每个人造一辆,只会在系统内制造大量无用的垃圾。


已经把程序怎么从源代码变成指令、数据,并装载到内存里面,由CPU一条条执行下去的过程讲完了。希望你能有所收获,对于一个程序是怎么跑起来的,有了一个初步的认识。

5 推荐阅读

想要更加深入地了解动态链接,推荐你可以读一读《程序员的自我修养:链接、装载和库》的第7章

image.png

image.png

里面深入地讲解了,动态链接里程序内的数据布局和对应数据的加载关系。

参考

  • 深入浅出计算机组成原理
目录
相关文章
|
6月前
|
存储
计算机组成原理(5)----CPU的基本结构
计算机组成原理(5)----CPU的基本结构
169 0
|
6月前
|
存储 Unix 程序员
计算机组成原理(5)----指令系统(2)
计算机组成原理(5)----指令系统
633 1
|
6月前
|
存储 人工智能 C语言
计算机组成原理(5)----指令系统(1)
计算机组成原理(5)----指令系统
99 1
|
存储 NoSQL 网络协议
关于操作系统、计算机组成原理、编译系统、数据库原理、计算机网络原理总结
关于操作系统、计算机组成原理、编译系统、数据库原理、计算机网络原理总结
152 0
|
12月前
|
存储 编译器 芯片
【计算机组成原理】知识点巩固 - 存储器概述
【计算机组成原理】知识点巩固 - 存储器概述
4519 1
|
存储 编译器 C语言
计算机底层知识之汇编语言
汇编语言和本地代码是一一对应的 推荐阅读指数⭐️⭐️⭐️⭐️⭐️ 不会转换成本地代码的伪指令 推荐阅读指数 ⭐️⭐️⭐️ 汇编语言的语法是操作码 + 操作数 推荐阅读指数⭐️⭐️⭐️⭐️⭐️ mov指令 推荐阅读指数 ⭐️⭐️⭐️ 对栈进行push 和 pop 推荐阅读指数 ⭐️⭐️⭐️ 函数调用机制 推荐阅读指数 ⭐️⭐️⭐️⭐️⭐️ 函数内部的处理 推荐阅读指数 ⭐️⭐️⭐️⭐️⭐️ 全局变量用的内存空间 推荐阅读指数 ⭐️⭐️⭐️ 循环处理的实现方法 推荐阅读指数 ⭐️⭐️⭐️⭐️⭐️
110 0
计算机底层知识之汇编语言
#计算机组成原理# (学第四章先看!!)第四章 存储器简述
#计算机组成原理# (学第四章先看!!)第四章 存储器简述
73 1
#计算机组成原理# (学第四章先看!!)第四章 存储器简述
|
存储 JavaScript 算法
计算机组成原理系列(二):计算机编码全解析
你是不是工作了很多年了,一直没搞清楚计算机中的各种编码规则,虽然平时都会使用,但是内部机制原理一直都是之其然而不知其所以然,开发中也会经常涉及到这块内容,但都没有太多重视
计算机组成原理<六>——指令系统(思维导图)
计算机组成原理<六>——指令系统(思维导图)
计算机组成原理<六>——指令系统(思维导图)
|
存储 编译器 C语言
计算机组成原理 第二章
计算机组成原理 第二章
281 0