美文网首页计算机基础
程序的链接(四):静态链接

程序的链接(四):静态链接

作者: N8_xEnn7nA1 | 来源:发表于2018-07-06 07:30 被阅读0次

Step 1:静态链接的符号解析

依旧用一个简单的C程序来说明。

首先,自定义一个静态库文件:


image.png

可以看到,程序中有如下函数调用关系:

调用关系:main—>myfunc1—>printf

符号的解析过程,用到了3个集合,分别是:

  • E:将被合并以组成可执行文件的所有目标文件集合;
  • U:当前所有未解析的引用符号的集合
  • D:当前所有定义的符号的集合

具体解析过程:

一开始E、U、D 三个集合都为空,首先扫描main.o,把它加入E,同时把myfunc1加入U,把main加入D;
接着扫描mylib.a,将U中的所有符号(本例为 myfunc1)与mylib.a中的所有目标模块(本例为myproc1.o和myproc2.o)进行匹配,发现在myproc1.o中定义了myfunc1,故将myproc1.o加入E,将myfunc1从U移到D。在myproc1.o中还发现未解析的符号printf,故将printf加入U。不断在mylib.a的其他目标模块中进行匹配U中的符号,直到U、D都不再变化。此时U中还有一个未解析的符号printf,而D中有main和myfunc1,因为模块myproc2.o没有被加入E中,所以它被丢弃。
接着扫描默认的库 libc.a,发现其目标模块printf.o中定义了printf,故将printf.o加入E,printf从U移到D,同时把它定义的所有符号加入D,而所有的未解析符号加入U。处理完libc.a时,U一定是空的。

如果将上面的命令 gcc -static -o myproc main.o ./mylib.a 改为:
gcc -static -o myproc ./mylib.a main.o 结果会怎样?

首先,会扫描mylib.a,因为它是静态库,所以应该根据U中的未解析符号来逐个匹配mylib.a中的目标模块,但是一开始时,U是空的,所以mylib.a中的所有目标模块都会被丢弃;接着扫描main.o,将其加入E,发现在main.o中有未解析的符号myfunc1,将其加入U。符号解析结束,结果到了最后,U中的myfunc1都不能被解析,故链接出错!

因此,总结链接器对符号的外部引用的解析算法要点如下:

  • 按照命令行给出的顺序扫描.o和.a文件
  • 扫描期间将当前未解析的符号引用记录到U中
  • 每遇到一个新的.o或.a中的模块,都试图用其来解析U中的符号
  • 如果扫描到最后,U中还有未被解析的符号,则发生错误
    避免该问题的方法就是将静态库放在编译命令的最后。

Step 2:静态链接的符号重定位

符号解析完成后,就可进行重定位了。

前面的链接概述的文章提到过,符号的重定位分为以下三步:

  1. 合并相同的节

将集合E的所有目标模块中相同的节合并成新节。例如,所有 .text节合并作为可执行文件的 .text节

  1. 对符号定义进行重定位(确定地址)

确定新节中所有的符号定义在虚拟地址空间中的地址。例如,为函数确定首地址,进而确定每条指令的地址,为变量确定首地址

  1. 对符号引用进行重定位(填入地址)

修改.text节和.data节中对每个符号的引用(地址)
需要用到 .rel.text 和 .rel.data节中保存的重定位信息

这里有必要对重定位信息进行说明,如图:

image.png

下面是一个符号重定位的示例,如图:

① 首先进行符号解析


image.png

符号解析的结果是:
E中有main.o和swap.o两个模块,D中有所有定义的符号。
在main.o和swap.o的重定位条目中有重定位信息,反映符号引用的位置、绑定的符号名、重定位类型。

② 合并相同的节


image.png

③ 具体看一看main.o和swap.o的符号重定位的过程:
main.o 重定位前

image.png

main.o 中的符号表

image.png

通过这个例子,介绍一下R_386_PC32R_386_32的重定位方式,如下图:

  1. R_386_PC32


    image.png
  2. R_386_32


    image.png
    image.png
    image.png

swap.o的重定位

image.png
image.png
image.png

相关文章

  • 程序的链接(四):静态链接

    Step 1:静态链接的符号解析 依旧用一个简单的C程序来说明。 首先,自定义一个静态库文件: 可以看到,程序中有...

  • 程序编译链接(四)-- 静态链接

    对于链接器来说,整个链接的过程,就是将几个输入目标文件加工后合并成一个输出文件。那么对于多个输入的文件,链接器是如...

  • 静态链接(四)

    重定位 重定位表 链接器为了知道有哪些指令需要被重定位,所以需要这样的一个表 一个重定位表往往就是ELF文件中的一...

  • 四、静态链接

    1.源代码(a.c b.c) 结合$ readelf -S和$ readelf -s的输出,可以获取到两个目标文件...

  • 四、静态链接

    可执行文件中的代码段和数据段由目标文件合并而来,如何合并的呢? 1. 两步链接(Two-pass Linking)...

  • 《程序员的自我修养》笔记

    第二章 静态链接 疑问: 问什么静态链接不会把所有代码链接进程序 为什么要静态链接 被隐藏的过程 gcc hell...

  • 操作系统 - 存储管理

    存储器工作原理 程序链接 链接库 静态链接 程序装载到内存和运行前链接 动态链接 内存一边装载程序一边链接,生成可...

  • 操作系统

    • Linux静态链接和动态链接; (转)静态链接和动态链接1、静态链接静态链接方法:#pragma comme...

  • 静态库和共享库

    1、静态库 静态库就是一些目标文件的集合,以.a结尾。静态库在程序链接的时候使用,链接器会将程序中使用到函数的代码...

  • gcc程序编译的静态链接和动态链接

    在链接阶段中,所有对应于源文件的.o文件、"-l"选项指定的库文件、无法识别的文件名(包括指定的.o目标文件和.a...

网友评论

    本文标题:程序的链接(四):静态链接

    本文链接:https://www.haomeiwen.com/subject/zvtvuftx.html