R_X86_64_32
重定位一个使用 32 位绝对地址的引用
通过绝对寻址,CPU 直接使用在指令中编码的 32 位值作为有效地址,不需要进一步修改

回顾重定位算法中的代码片段

0000000000000000 <main>:         
   0:   48 83 ec 08             sub    $0x8,%rsp
   4:   be 02 00 00 00          mov    $0x2,%esi
   9:   bf 00 00 00 00          mov    $0x0,%edi        %edi = &array
                        a: R_X86_64_32 array            Relocation entry
   e:   e8 00 00 00 00          callq  13 <main+0x13>   sum()
                        f: R_X86_64_PC32 sum-0x4        Relocation entry
  13:   48 83 c4 08             add $0x8,%rsp
  17:   c3                      retq

再回顾一下重定位符号引用中的算法伪代码实现

重定位符号引用

foreach section s { //对于每个节
    foreach relocation entry r { //对于每个重定位条目,条目在节上
        refptr = s + r.offset;  /* ptr to reference to be relocated */
    
        /* Relocate a PC-relative reference */
        if (r.type == R_X86_64_PC32){
            refaddr = ADDR(s) + r.offset; /* ref's run-time address */
            *refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr);
        }
 
        /* Relocate an absolute reference */
        if (r.type ==R_X86_64_32)
            *refptr = (unsigned) (ADDR(r.symbol) + r.addend);
    }
}

第 1 行和第 2 行在每个节 s 以及与每个节相关联的重定位条目 r 上迭代执行
假设每个 s 是一个字节数组,每个重定位条目 r 是一个类型为 Elf64_Rela 的结构
假设当算法运行时,链接器已经为每个节(用 ADDR(s) 表示)和每个符号都选择了运行时地址(用 ADDR(r.symbol) 表示)
ADDR(s) 表示 节的地址
ADDR(r.symbol) 表示 符号的运行时地址
第 3 行计算的是需要被重定位的 4 字节引用的数组 s 中的地址,也就是这个符号在节中的相对位置
如果这个引用使用的是 PC 相对寻址,那么它就用第 5 ~ 9 行来重定位
如果该引用使用的是绝对寻址,它就通过第 11 ~ 13 行来重定位

Link to original

a: R_X86_64_32 array Relocation entry 给出了 r.offset = 0xa
第 4 行中,mov 指令将 array 的地址(一个 32 位立即数值)复制到寄存器%edi 中。mov 指令开始于节偏移量 0x9 的位置,包括 1 字节操作码 Oxbf,后面跟着对 array 的 32 位绝对引用的占位符
可以得到对应的占位符条目 r 包括 4 个字段:

r.offset = 0xa
r.symbol = array
r.type   = R_X86_64_32
r.addend = 0

这些字段告诉链接器要修改从偏移量 0xa 开始的绝对引用,这样在运行时它将会指向 array 的第一个字节。现在,假设链接器巳经确定 ADDR(r.symbol) = ADDR(array) = 0x601018
链接器使用算法的第 13 行修改了引用:

*refptr = (unsigned) (ADDR(r.symbol) + r.addend)
        = (unsigned) (0x601018       + 0)
        = (unsigned) (0x601018)

在得到的可执行目标文件中,该引用有下面的重定位形式:
4004d9: bf 18 10 60 00 mov $0x601018,%edi %edi = &array

Note

请注意:我们算出了*refptr = 0x601018
但是最最终得到的可执行目标文件中,它以小端序存储,也就是得到了
bf 18 10 60 00
其中bf是 1 字节操作码 Oxbf,后面就是小端序存储的运行时绝对地址