程序员

3、静态链接

2017-02-23  本文已影响58人  eesly_yuan

上一篇说到链接主要包括地址和空间分配、符号决议、重定位这三部分,本篇文章将针对这三部分进行一个详细说明

链接过程

ld a.o b.o -e main -o ab

链接过程实际上将多个目标文件.o的同类段进行合并处理合并成一个elf的执行文件,这个过程中涉及到一个问题就是不同目标文件的段如何进行合并?

符号解析和重定位

链接之前,目标文件中对其他模块中符号的引用的位置通常填入一个临时的假地址,包括两种类型

而链接时重定位就是找到被引用符号在最终输出文件的地址,利用该地址对这些需要调整的临时假地址进行修正。下面分析一下实现这个过程中涉及的两个问题

common块机制

链接通常允许弱符号(定义未初始化的全局变量)机制,即允许同一个符号定义在多个文件中,由于链接过程中并不涉及符号的类型,只知道符号所占空间的大小,这将导致链接器进行符号选择的问题,链接器通常采用common块机制:最终选择占用空间最大的那个弱符号,或者说给该符号分配最大的空间
具体的关于多个目标文件中强弱符号的选择规则如下

C++相关问题

c++由于其语言特性需要编译链接器进行支持,这里主要说明两方面

1、假设有模板类M,文件a.cpp使用并实例化了M,文件b.cpp也使用并实例化了相同类型的M,那么在a.o和b.o的代码段中都将存在M实例的代码,这两部分代码是完全相同的,因此出现了代码冗余的问题(空间浪费、寻址易出错、运行效率低)。
针对这个问题目前比较主流的做法是:将每个模板的实例代码都放在一个单独的段里面,这个段里面就只包含这一个模板实例,并且按照一定的方式对这种段进行命名,这样当两个.o文件都包含M代码实例时,就可以区分这些相同的代码段并进行去重操作,这种类型的段在gcc中被称之为link once。
·
2、对于一个有虚函数的类会有一个与之相对应的虚函数表,编译器会在用到该类的多个目标文件中包含该虚函数表的代码,造成代码重复。
针对这个问题的解决方式与上面的方式类似

_start->init->main->fini

与上面对应的elf中存在两个段.init和.fini,存放在这两个段中的代码将分别在上述init阶段和fini阶段执行,将全局构造和析构分别放入上述段也就可以实现全局对象的正常构造和析构了。

静态库链接

一般一种语言开发都会附带一个语言库,这些库通常是对系统调用的包装,例如linux下glibc库。通常这些语言库都包含两个版本:静态库和动态库,这里先主要介绍静态库。静态库实际上是一组目标文件的集合,linux下可以利用ar命令将多个目标文件打成一个静态库也可以查看一个静态库中包含哪些目标文件。编译时使用静态库链接方式,链接器只会将静态库中使用到的目标文件链接到最终的输出文件中

链接过程控制

上述介绍到链接实际是地址空间分配和符号重定位,针对这个链接过程,链接器提供了一定的控制方式

ld -T mylink.scripts
上一篇下一篇

猜你喜欢

热点阅读