对于X86平台下的ELF文件的重定位入口所修正的指令寻址方式只有两种:绝对近址32寻址和相对近址32寻址。
这两种指令修正方式每个被修正的位置的长度都为32位,即4个字节,而且都是近址寻址,不用考虑Intel的段间远址寻址。r_info成员的低8位表示重定位入口的类型。
X86基本重定位类型
宏定义 值 重定位修正方法
R_386_32 1 绝对寻址修正 S + A
R_386_PC32 2 相对寻址修正 S + A - P
A = 保存在指令中被修正位置的值
P = 被修正的位置(相对于段开始的偏移量或者虚拟地址),该值可以通过r_offset计算得到。
S = 符号的实际地址,即由r_info的高24位指定的符号的实际地址。
因为a.o中shared和swap需要地址重定位,以此为例子说明重定位地址修正方法。用objdump -r a.o可以得到a.o中需要重定位的符号如图4.2.7所示:
***图4.2.7(同4.2.4相同)***
从图中可知,shared的重定位类型为R_386_32,因此为绝对寻址修正方式。那么S的值怎么得到,可以从a.o,b.o链接成的可执行文件的符号表中得到,可执行文件的符号表如图4.2.8:
***图4.2.8***
从图中看出shared的实际地址为0x08049158,即是S的值。从a.o反汇编指令中可知A的值,如图4.2.9所示:
***图4.2.9***
从图4.2.7中得知shared相对段开始的偏移为0x15,所以A的值是0x0。那么shared重定位后的地址为S + A = 0x08049158 + 0x0 = 0x08049158。怎样验证该数值的正确性?可以通过可执行文件的反汇编代码验证,如图4.2.10所示:
***图4.2.10***
指令的地址,0x07 + 0x080480b9 = 0x080480c0,该地址即为swap函数的地址。
***图4.2.11***