标签归档:链接

处理目标文件工具

摘自 深入理解计算机系统
在unix系统中有大量的工具可以查看和处理目标文件。
例: AR : 创建静态库 插入 删除 列出 提取成员。
STRINGS : 列一个一个目标文件中所有可打印的字符串
STRIP: 从目标文件中删除符号表信息
NM 列出一个目标文件的符号表中定义的符号
SIZE 列出目标文件中的节的名字和大小
READELF 显示一个目标文件的完整结构,包含ELF头中编码的所有信息。包含SIZE和NM
OBJDUMP 反汇编.text节中的二进制指令。

链接总结

摘自 深入理解计算机系统
链接(ld)是一个源文件变成可执行文件所进行的最后操作,链接可以由静态编译器编译生成,也可以加载运行时由动态链接器完成,链接器的功能是将目标文件转换为可执行的二进制文件的过程,由三种不同的链接操作方式,可重定位的 可执行 共享的。
1 可重定位的目标文件由静态链接库组合转换为可执行文件。链接器之重定位
2 可执行的目标文件
3 共享目标文件(共享库)是在运行时由动态链接器链接和加载运行的。 共享目标文件应用
链接器的主要任务: 符号解析 重定位
符号解析:链接器将目标文件中的每个全局符号都绑定到一个唯一的定义,而重定位确定每个符号的最终存储器地址,并修改对目标的引用地址。
静态链接器可以将多个可重定位目标文件组合成一个单独的可执行目标文件。多个目标文件可以定义相同的符号,而链接器对每一个符号进行解析并赋予新的地址,加载器将可执行文件的内容映射到存储器,并运行程序。
动态链接器生成的可执行文件,还未解析共享库中的程序和数据的引用。在加载时,加载器将部分链接的可执行文件映射到存储器中,然后通过调用动态链接器,加载共享库和重定位程序的引用来完成链接任务。

与位置无关的PIC

摘自 深入理解计算机系统
共享库的一个主要目的是允许多个正在运行的进程共享存储器中的相同库代码,因为可以节约宝贵的存储器资源,那么多个进程是如何共享一个程序的copy。
方法一 给每个共享库分配一个事先预备的专用的地址空间,加载器将共享库加载至这个空间中,这种方法会产生以下缺点:
1 即使程序不被使用,也会占用了一个存储器空间, 会造成空间上的浪费。
2 如果库被修改后变大,那么还需要另外寻找适合存储库的空间,以前的空间被浪费掉。
3 如果系统拥有成千上万个库,那么系统的存储器会被这么库占用很多,造成很大的空间浪费。

方法二 编译库代码,使在任何地址都可以加载和执行这些代码,这种代码就叫做PIC(position-independent code PIC)。


PIC数据引用:
无论在存储器中的任何地方加载一个目标模块/共享目标模块,数据段都会被分配在代码段后面,估代码段的任何指令和数据段的任何变量之间都是一个运行时常量的距离。利用这一点,编译器在数据段开始的位置创建一个全局偏移量表(GOT)。(GOT)包含每个被这个目标模块引用的全局数据目标的表目。编译器还为GOT每个表目生成一个重定位记录。在加载时,动态链接器会重定位GOT中的每个表目,使得它包含正确的绝对地址。每个引用全局数据的目标模块都有一张自己的GOT。
下面代码为GOT将变量修改为绝对地址(引用地址)
call L1
L1: popl %ebx;
addl $VAROFF , %ebx
movl (%ebx) , %eax
movl (%eax) , %eax

PIC 函数调用:
call L1
L1: popl %ebx;
addl $PROCOFF ,%ebx
call *(%ebx)