小代码模型中相对偏移的计算

Ric*_*cky 5 c++ assembly x86-64 abi relocation

我试图了解小代码模型中使用的 RIP 相对偏移量。也许互联网上有关此主题的唯一可用资源是: https: //eli.thegreenplace.net/2012/01/03/understanding-the-x64-code-models 但在这篇文章中也有一些事情不清楚。我使用这个简单的程序来了解一些事情:

// sample.cc
int arr[10] = {0};
int arr_big[100000] = {0};
int arr2[500] = {0};
int main() {
  int t = 0;
  t += arr[7];
  t +=arr_big[6];
  t += arr2[10];
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

汇编:g++ -c sample.cc -o sample.o

.text 部分的目标代码:( objdump -dS sample.o)

Disassembly of section .text:

0000000000000000 <main>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
   b:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 11 <main+0x11>
  11:   01 45 fc                add    %eax,-0x4(%rbp)
  14:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 1a <main+0x1a>
  1a:   01 45 fc                add    %eax,-0x4(%rbp)
  1d:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 23 <main+0x23>
  23:   01 45 fc                add    %eax,-0x4(%rbp)
  26:   b8 00 00 00 00          mov    $0x0,%eax
  2b:   5d                      pop    %rbp
  2c:   c3                      ret
Run Code Online (Sandbox Code Playgroud)

重定位表:( readelf -r sample.o)

Relocation section '.rela.text' at offset 0x1a8 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
00000000000d  000300000002 R_X86_64_PC32     0000000000000000 arr + 18
000000000016  000400000002 R_X86_64_PC32     0000000000000040 arr_big + 14
00000000001f  000500000002 R_X86_64_PC32     0000000000061ac0 arr2 + 24
Run Code Online (Sandbox Code Playgroud)

从这个答案中我了解到,偏移量是必须修改的文本部分的第一个字节。编译器事先不知道任何可重定位条目的位置,这就是为什么它创建00将由链接器填充的部分。一旦我们查看输出,这个解释就可以理解objdump。第一个重定位有偏移量0xd,.text 中的“第 d”字节是该行中包含 0 的部分8b 05 00 00 00 00

因此,链接器将在该位置填充 的地址arrR_X86_64_PC32意思是“取符号值,加上加数并减去偏移量”。我不明白这个计算。“符号价值”是什么意思?在小代码模型中,所有偏移量都将相对于指令指针(RIP)。因此,对于行mov 0x0(%rip),%eax,RIP 值将是下一条指令地址 ( 0x11)。偏移量为0xd,加数为0x18。因此,如果我们将加数添加到 RIP 并减去偏移量 ( 0x11 + 0x18 - 0xd),则它变为0x1c第 7 个整数(1 int = 4 字节)。这是有道理的,因为该指令正在尝试访问 array 中的第七个索引arr。我不明白的是:

  1. RIP和RIP之间的相对偏移是如何arr计算的。它是由链接器在链接时计算的吗?
  2. 为什么需要是 32 位?
  3. sym. 是什么意思?重定位表中的值表示什么?我假设它是符号在其部分中的相对位置。例如,arr具有 sym 值0,因为它是 .bss 部分中的第一个条目。arr_big40作为符号。值,因为它是 40 字节长后的第二个条目arr,并且arr2具有0x61ac0sym。arr_big 和 arr 之后的值(40 + 100000 字节)。

提前致谢。

vit*_*oft 3

链接器将段存储到以图像基址绝对地址(例如 0x0040_0000)开始的内存中。.text节存储在 0x0040_1000 处,.data 节存储 在 0x0040_2000 处。符号main
的值位于.text节中的偏移量 0 处,即 0x0040_1000。符号arr 的值位于.data节中的偏移量 0 处,即 0x0040_2000。 只有这样,搬迁问题才能得到解决。

Offset Info Type Sym. Value Sym. Name + Addend
00000000000d 000300000002 R_X86_64_PC32 0000000000000000 arr + 18

Relocation.Info(2)告诉我们它的类型是程序计数器相对32位字段重定位.text节中偏移量0xd处,所以它的绝对虚拟地址(VA)是0x0040_100d。

Relocation.Info (3) 表明它与符号表中的第 3 项相关,该项代表VA 0x0040_2000 的.data节。

了解所有符号的最终地址后,链接器现在可以执行计算。
在上面提到的语句中,
b: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 11 <main+0x11>
它采用目标符号arr VA 0x0040_2000,减去字段偏移量 0x0040_100d,添加加数 0x18,然后将结果 0x100B 添加到编译器向指令体发出的任何内容(值 0x00000000)。
CPU 会将语句视为mov 0x0(%rip),%eaxb: 8b 05 0b 10 00 00正如您在调试器中看到的那样。该指令的 RIP 是 0x0040_1011,当您将 32 位 imm 值 0x100b 添加到 RIP 时,寄存器 EAX 将从 VA 0x0040_201c 加载,这是arr的第 7 个 DWORD 。

  1. sym. 是什么意思?重定位表中的值表示什么?

这是readelf为了方便起见,由目标值+加数计算出来的信息,实际上它只是作为Rela.Info的高位双字间接包含在重定位记录中。以序数的形式存入符号表。