符号解析与重定位

重定位

编译器并不知道引用符号的真正地址,暂时用临时的假地址代替着,把真正的地址计算工作留给了链接器,链接器可以根据符号的地址对每个需要重定位的指令进行地位修正。

重定位表

在ELF文件中,有一个叫重定位表的结构专门用来保存这些鱼重定位相关的信息。对于可重定位的ELF文件来说,它必须包含有重定位表,用来描述如何修改相应的段里的内容。
每个要被重定位的地方叫一个重定位入口(Relocation Entry),重定位入口的偏移(Offset)表示该入口在要被重定位的段中的位置,“RELOCATION RECORDS FOR [.text]”表示这个重定位表是代码段的重定位表。
重定位入口的定义如下:

typedef struct{
    Elf32_Addr r_offset;    // 重定位入口的偏移
    Elf32_Word r_info;      // 重定位入口的类型(低8位)和符号(高24位表示符号在符号表中的下标)
}Elf32_Rel;

符号解析

我们平时在编写程序的时候最常碰到的问题之一,就是链接时符号未定义。导致这个问题的原因很多,最常见的一般都是链接时缺少了某个库,或者输入目标文件路径不正确或符号的声明与定义不一样。所以从普通程序员的角度看,符号的解析占据了链接过程的主要内容。

其实重定位过程也伴随着符号的解析过程,每个目标文件都可能定义一些符号,也可能引用到定义在其他目标文件的符号。重定位的过程中,每个重定位的入口都是对一个符号的引用,那么当链接器需要对某个符号的引用进行重定位时,它就要确定这符号的目标地址。这时候链接器就会去查找由所有输入目标文件的符号表组成的全局符号表,找到相应的符号后进行重定位。若找不到就报符号未定义错误。

指令修正方式

不同的处理器指令对于地址的格式和方式都不一样。这些寻址方式有如下几方面的区别:
近址寻址或远址寻址
绝对寻址或相对寻址
寻址长度为8位、16位、32位或64位

但对于32位x86平台下的ELF文件的重定位入口所修正的指令寻址方式只有两种:
绝对近址32位寻址
相对近址32位寻址

每个被修正的位置的长度都为32位,即4个字节。

宏定义 重定位修正方法
R_386_32 1 绝对寻址修正 S+A
R_386_PC32 2 相对寻址修正 S+A-P

A=保存在被修正位置的值
P=被修正的位置(相对于段开始的偏移量或虚拟地址),注意,该值可通过r_offset计算得到
S=符号的实际地址,即由r_info的高24位指定的符号的实际地址

posted @ 2019-03-05 19:27  睿阳  阅读(1778)  评论(0编辑  收藏  举报