深入理解计算机系统—链接——静态链接

有人被365黑过钱吗 2025-09-03 23:51:38 admin 访问量: 6874 评分: 828
深入理解计算机系统—链接——静态链接

程序执行前经历了啥

当我们编写了一个程序,你想法设法让他运行,在你的编辑器编译运行。

编译是啥,运行前经历了啥。

用一张图就是这样表示的。

预处理器cpp:

gcc -E a.c -o a.i

假设看一个程序没有include:

加入加了include

所以预处理器cpp就是对这个程序进行预处理,可以展开头文件或者宏替换还有去掉注释,有时候头文件里面有条件编译,

也可以翻译成一个.i文件。

编译器cc1:

编译阶段是检查语法,生成汇编:gcc -S a.i -o a.s

将预处理过的.i文件搞成了汇编程序,至于里面进行了怎样的复杂过程,怎样优化,我也不是很清楚,有时间研究,只要知道它是用来翻译成汇编程序就行了。

注意上面的两个文件都是ASCII文件

汇编器as:

汇编代码转换机器码 gcc -c a.s -o a.o

这个汇编器之后就是一个可重定位的目标程序了,等会儿看看啥样子

链接器:

链接过程将多个目标文以及所需的库文件链接成最终的可执行文件

gcc a.o -o a

今天就重点来初识一下链接器所做的链接过程

静态链接

静态链接就是根据一系列可重定位的目标文件和命令行的参数,来生成一个已经完全链接的,而且可以加载运行的可执行文件的过程

不知道什么意思没有关系,我们一步一步来梳理就行。

这个静态链接由一个静态链接器完成,主要执行两个过程。

一个是符号解析,一个是重定位。

又懵了,什么是符号,解析他干嘛,重定位又是啥?

还是一步一步来

首先要知道啥时符号吧

符号:不说了,上图吧。

似乎明白了,不就是一些符号啥的嘛,好像没啥了不起的。先有个印象

符号解析这个过程先不说,先来看看那个我们之前所说的可重定位的目标文件。

它是经汇编程序翻译过来的二进制文件。

首先要知道Linux系统使用可执行可链接格式,即ELF。

可重定位文件分成了一节节的内容,即符合ELF格式的一种二进制文件。

先来上一份代码吧

int count = 0;

int boy = 1;

int k;

void main(){

static int p = 1;

count += p;

}

我们使用readelf -S b.o查看一下内容

我们需要重点观察.bss,.data,.text.symtab

我们通过图片可以知道它是一节节的组成的。

我们重点在于符号表.symtab

使用readelf -s b.o(这里是小s)可以查看符号表的内容

.symtab:

就是通过readelf -s> 命令弄出来的,上面这张图,value对应的在对应节的偏移量,Size大小,Type类型,Bind是本地还是全局还是弱符号,Ndx对应于ELF文件(可重定位目标文件)的哪一节。

.bss:

对应上面图片Ndx项的4,用于存放未被初始化的全局变量和静态C变量,但是有个情况,如果你指定了一个为初值为0的变量,就像上面的count,它是一个初始化为0的全局变量,但是它被分配在了.bss字段。还需要注意的就是,如果一个静态变量被分配空间的话,它有个特殊的,它只适合本地模块,也就是说只需要在本地保证唯一就行了,就算其他模块有同名的强符号或者弱符号,本地模块只会引用本地的这个静态变量,除非你指定了用外部模块的。对于bss更细微的定义就是,它一般只保存未初始化的静态变量和初始化位0的全局变量,静态变量,而未初始化的全局变量暂时在符号表中定义为COMMON,就像上面的k一样。

.data:

对应上面图片的3,用于存放已经初始化的全局变量和静态C变量,但是初始值为0的没有分配在这个地方,和上面一样。

.text:

存放是编译后的机器代码

我们了解了符号和符号表,就可以来进行符号解析了

符号解析

就是将某个模块的符号引用与这个符号在另一个模块的定义相关联

写了两个程序

我们把他们编译成可重定位的文件

有三种集合,链接器进行符号解析时,需要创建维护这三个集合。

E:合并在一起的所有目标文件(还未重定位)

U:没有解析的符号(定义符号和引用符号还没有被建立联系)

D:定义符号的集合

当链接器接收到了一个可重定位文件

看看它是不是库文件

库文件:将所有没有解析的符号(U)与库文件匹配,如果匹配上了,就将匹配的模块放入E中,然后将这个U中的符号放到D中,知道U和D不在变化,库文件剩下的全不要了。

非库文件:就是可重定位的目标文件,先把它放到E中,分别将未解析的符号和定义的符号放到U和D中,如果D中有未解析符号的定义,那么就可以将U中的那个未解析的符号和D中定义的相关联。

比如如果链接上面的两个可重定位文件

虽然说符号建立的关联,但是仅仅建立了管理而已,我们根本不知道符号对应地址在哪里。

你看这些全是0,根本不知道对应的符号地址在哪里,你要它怎么去执行命令,这不是为难它吗?

所以我们还需要一个过程,就是重定位

重定位

重定位就是为每个符号分配对应的地址

合并相同类型的节,然后链接器将运行时的内存地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号。

然后对定义符号进行重定位

对引用符号进行重定位,那么每个被引用符号的位置,都为改成对应分配的地址

你看将两个可重定位文件重定位后:

所有的地址都变了。

相对寻址

对于一个重定位条目,里面保存了一个数据结构的信息

第一就是给定重定位偏移量offset,还有就是修正值addend,还有重定位寻址类型(相对,绝对)

还有就是重定位的符号r.symbol

计算机会给我们的信息就是每个节的信息(比如.text代码节,记作ADDR(s)),然后还有重定位符号地址(ADDR(r.symbol))

我们先根据重定位偏移量找到我们需要重定位的地址address = ADDR(s)+offset

然后我们要根据重定位符号地址和修正值,来更新重定位的引用地址

则ADDR(r.symbol) +addent-address就填充进我们要重定位的引用地址值

绝对寻址:

绝对寻址比较粗暴简单,直接对符号地址加以修正 ADDR(r.symbol+addend)即可

相关数据

当孩子说我要做公主,你该怎么做?
365bet足球在线

当孩子说我要做公主,你该怎么做?

08-17 ↗ 9608
魔兽世界要塞建造指南
365bet足球在线

魔兽世界要塞建造指南

08-20 ↗ 584
dnf公会战耳环多久
有人被365黑过钱吗

dnf公会战耳环多久

08-01 ↗ 7835
卡仕达导航价格表
365bet足球在线

卡仕达导航价格表

07-03 ↗ 2094
奇迹mu+无赖,奇迹无赖多久变白名
有人被365黑过钱吗

奇迹mu+无赖,奇迹无赖多久变白名

07-25 ↗ 4584
汉魏六朝“乐舞赋”的音乐史料价值
365bet足球在线

汉魏六朝“乐舞赋”的音乐史料价值

07-24 ↗ 6889
足球有哪四种颜色组合
有人被365黑过钱吗

足球有哪四种颜色组合

07-15 ↗ 2686