静态链接

6 篇文章 0 订阅
6 篇文章 0 订阅

根据前面知道的目标文件的各个段,

现在想把多个目标文件链接到一起,为什么不简单就把各个目标的各个段相加合起来?

1. 输出文件将会有很多零散的段

2.由于每个段都需要和有一定的地址和空间对齐,所以这样做也很造成很多内部碎片

 

很自然的我们想起 相似的段进行合并。

关于2步链接:

1. 空间与地址分配

2. 符号解析与重定位。

关于 内存地址 都是指的VMA, 虽然很多地方LMA 都是等于 VMA的,但是有些特殊的嵌入式系统中,特别是那些程序存放在ROM 的系统中的。

 

在链接之前,目标文件中的所有段的VMA 都是0, 这个可以通过命令objdump -h a.o进行观察,因为这时候VMA还没有被分配,所以他们默认都为0,等到链接过之后,可执行文件ab VMA 已经被分配了, objdump -h ab。

在linux下,ELF可执行文件默认地址从地址0x08048000开始的。

 

重定位:

我们可以先观察下 链接前的目标文件

objdump -d a.o

 

我们会发现,对于a.c里面的2个引用 "shared","swap",由于编译器不知道这2个外部引用定义在其他的目标文件中,所以会给个暂时的地址给他们, 如0x00000000,或者是类似的0xFCFFFFFF,这里有个指令: 近址相对位移调用指令,

e8 fc ff ff ff   后面四位就是相对于调用指令的下一个指令的偏移量。

 

然后我们在看看  最后出现的可执行的文件 ab

objdump -d ab

经过了修正,shared, swap 都有自己真的调用地址。

 

实现这个功能就是重定位,首先每个目标文件都有一张重定位表,

objdump -r a.o

从里面可以看到

在a.o中所有引用的外部符号的地址。接下来就是链接需要做的 指令修正:

有2中修正:

1.绝对寻址修正: S+A,

2.相对寻址修正:S+A-P

 

这个符号运用什么修正,取决于我们上面 他在重定位表中的信息。

 

绝对寻址修正:以以前a.o为例子,

S是符号shared的实际地址,为0x3000

A是被修正位置的值,即0x0000

所以最后这个重定位入口修正后地址为0x3000+0x0000=0x3000

 

相对寻址修正:

S是符号swap的实际地址,0x20000

A是被修正位置的值 0xFCFFFFFF

P是被修正的位置,0x1000+0x27.

 

重复代码消除,

比如说最典型的模板,如果不消除因为模板造成的空间浪费,甚至地址较易出错,

编译器一般会给模板单独做一个段出来,比如tmp.int段,tmp.double段。

 

全局析构和全局构造

其实在main函数被调用之前,为了程序能够顺利执行,要先初始化进程执行环境,如堆分配初始化,线程子系统等,C++全局构造函数就在这里执行,

所以main函数不是第一个执行的函数,linux下一般程序的入口是"_start"

全局析构 就是做些清理的工作。

 

ABI  主要是为了能让2进制文件可以复用,但是这个很难,很多因素决定了不能。

内置类型,

堆栈的分布方式

函数调用方式

......

C++比起C语言来说,它的2进制兼容得更不好。

静态库简单得堪称一组目标文件的集合,

ar -t libc.a

大家可以看libc.a 包括的很多.o文件。

 

下面讲的是链接过程中的控制:

 

一个没有用标准库实现的hello world,由于程序是晚上写,没有带到公司,时间原因就不写了。

主要是用汇编来调用linux系统调用。

运用ld 链接脚本把 我们觉得可以合并的段合并成一个,或者discard掉某些段。

接着是ld链接脚本的相关语法,如果有兴趣的可以去试一下。

BFD库,主要是抽象出目标文件的模式然后 使他能够支持更多的目标文件格式。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值