27|编译器在链接程序时发生了什么?
该思维导图由 AI 生成,仅供参考
静态链接 vs 动态链接
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了编译器在链接程序时的执行过程,主要围绕静态链接和动态链接的概念展开讨论。首先介绍了静态链接和动态链接的区别,以及它们对程序可执行文件的体积、执行效率和可移植性的影响。接着详细讲解了静态链接的处理过程,以 Linux 系统下的静态链接为例,从目标文件的基本结构到符号解析的具体流程进行了阐述。文章内容丰富,涵盖了编译器链接程序的技术细节,适合对编译器链接过程感兴趣的读者阅读。 在链接程序时,编译器首先进行符号解析,为每一个全局符号指定对应的“强弱”信息,并根据一定规则进行解析。接着进行重定位,将多个目标文件内相同类型的 Section 进行合并,并为这些 Section以及所有输出文件内使用到的符号指定运行时的 VAS 地址。链接器通过重定位表来修改对外部符号的引用地址,使得它们可以指向正确的运行时地址。最终,输出的可执行文件中,所有符号都有了正确的初始值和引用地址,程序可以被操作系统加载进内存,正常运行。 总的来看,静态链接被分为两个步骤:符号解析与重定位。符号解析是为应用程序使用的所有符号正确匹配对应符号定义的过程,而重定位过程中,链接器会将输入的多个目标文件的同类型 Section 进行合并,并为它们和所有程序使用到的符号分配运行时的 VAS 地址。紧接着,借助重定位表中的信息,链接器可以对上一步中得到的外部符号,进行地址及值上的修正。 本文内容涵盖了编译器链接程序的技术细节,对于对编译器链接过程感兴趣的读者具有很高的参考价值。
《深入 C 语言和程序运行原理》,新⼈⾸单¥59
全部留言(9)
- 最新
- 精选
- liu_liu老师有个疑问,S + A - P 中的 A 不是代表 Addend 吗?为什么是待修改位置上的值呢?
作者回复: 观察的很细致!这里确实是我把 ELF32 与 ELF64 下的重定位方式搞混了,因为比如对于 R_386_32 和 R_X86_64_64 来说,两个的计算方式都是 S + A,但前者中的 A 实际指的是被修改内存所在位置上的值,本质上就是符号的 addend。而对于后者,也就是 ELF64 来说,addend 被单独拎出来与重定向条目放到一起了。这里我来纠正一下,稍后我也会修改下文章内容!感谢! 这里我把 ELF 标准中的相关段落也放出来,大家在后面的学习中也注意类似的问题。文档(http://www.skyfree.org/linux/references/ELF_Format.pdf)第 29 页:“The SYSTEM V architecture uses only Elf32_Rel relocation entries, the field to be relocated holds the addend.”
2022-02-255 - 神佑小鹿链接器除了能将一组可重定位目标文件链接起来得到可执行目标文件以外,编译系统还提供一种机制,将所有相关的目标模块打包为一个单独文件,称为静态库(Static Library),可以作为链接器的输入。静态库是以存档(Achive)的文件格式存放在磁盘的,它是一组连接起来的可重定位目标文件的集合,有一个头部来描述每个成员目标文件的大小和位置,后缀为.a。使用静态库的优点有: 相关的函数可以被编译为独立的目标模块,然后封装成一个独立的静态库文件。 链接时,链接器只会复制静态库中被应用程序引用的目标模块,减少了可执行文件在磁盘和内存中的大小 应用程序员只需要包含较少的库文件名就能包含很多的目标模块,比如 ISO C99 中在 libc.a 静态库中包含了 atoi.o、scanf.o、strcpy.o 等可重定位目标模块,在 libm.a 静态库中包含了数学函数的目标模块。
作者回复: 回答的不错!
2022-05-112 - zxk在此基础之上,再向“右侧”移动 3 个字节,我们便可得到重定向的修改位置,即 0x400541。 老师想问下, 为什么需要向“右侧”移动 3 个字节?
作者回复: 因为从左侧可以看到,这一行的起始字节位置是 “0x40053e”,而实际发生重定向的位置是在这里后面数三个字节的地方,所以需要再加 3,得到正确的地址 “0x400541”。
2022-04-2421 - 神佑小鹿“可以看到,这个地址为十六进制值 0x601020。紧接着,A 表示符号 array 在重定位条目中的 Addend,即 -4。最后,P 表示当前重定向条目在输入文件中的修改位置。同样地,使用 objdump 命令,我们可以得到这个值。” 这个 P 是不是应该是符号占位符在可执行文件中的内存地址??
作者回复: 这里 P 实际上就是符号重定位想要去修改的那个符号,在文件中的偏移位置。
2022-05-11 - LDxy一个.a静态库文件可以包含多个.o目标文件2022-02-253
- 连瑞龙原文中: gcc main.c sum.c -o main # 生成可执行文件 main; gcc -c main.c -o main.o # 生成目标文件 main.o; gcc -c sum.c -o sum.o # 生成目标文件 sum.o; 这部分内容应该调整下顺序,否则报错后初学者可能不知道原因: gcc main.c sum.c -o main # 生成可执行文件 main; gcc -c sum.c -o sum.o # 生成目标文件 sum.o; gcc -c main.c -o main.o # 生成目标文件 main.o;2024-01-05归属地:北京
- Luke.o文件是编译器生成的文件,也是链接器的输入文件。 .a是linux下的静态库文件,gcc调用ar命令将多个.o文件合并,在GNU/Linux生态下,.a采用archive格式。 Windows平台上的.a和.lib都是采用COFF格式(Common Object File Format)。 记得以前用Borland平台的时候,还有tlb格式,Borland还提供了相关的工具(比如tlbimp)进行多种object格式之间的转换。2022-10-03归属地:江苏
- Jason Yu 于航文中我们提到的重定向与重定位实际上都是指 Location,它们是同样的意思。这里我在写这篇文章时没注意到翻译的一致性,大家可以注意一下哈。2022-05-15
- 神佑小鹿这个 “call” 指令是一条近址相对位移调用指令,它后面跟的是调用指令的下一条指令的偏移量2022-05-14