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

b0zn9rqh  于 2023-06-30  发布在  其他
关注(0)|答案(1)|浏览(113)

我试图了解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;
}

编译: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

重新定位表:(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

从这个answer我理解的是,offset是必须修改的文本部分的第一个字节。编译器事先不知道任何可重定位条目的位置,这就是为什么它创建了用00填充的部分,这些部分将由链接器填充。如果我们看一下objdump的输出,这个解释就可以理解了。第一个重定位的偏移量为0xd,.text中的“第d个”字节是此行8b 05 00 00 00 00中包含0的部分。
因此,链接器将在此位置填充arr的地址。R_X86_64_PC32表示“取符号值,加上加数并减去偏移量”。我不明白这个计算。他们所说的“符号价值”是什么意思?在小代码模型中,所有偏移量都是相对于指令指针(RIP)的。因此,对于行mov 0x0(%rip),%eax,RIP值将是下一个指令地址(0x11)。偏移量为0xd,加数为0x18。因此,如果我们将加数添加到RIP并减去偏移量(0x11 + 0x18 - 0xd),则变为0x1c,这是第7个整数(1 int = 4字节)。这是有意义的,因为该指令试图访问数组arr中的第7个索引。我不明白的是

  1. RIP和arr之间的相对偏移是如何计算的。是链接器在链接时计算的东西吗?
    1.为什么一定要32位?
    1.什么是sym重定位表中的值是否表示?我假设这是符号在其部分中的相对位置。例如,arr具有sym值0,因为它是.bss部分中的第一个条目。arr_big具有40作为sym。值,因为它是40字节长arrarr2之后的第二个条目,0x61ac0作为sym。在arr_big和arr之后的值(40 + 100000字节)。
    先谢谢你。
ecfdbz9o

ecfdbz9o1#

链接器将以图像基绝对地址(例如0x0040_0000)开始的部分存储到内存中。节**.text存储在0x0040_1000,.data存储在0x0040_2000。
symbol
main的值位于.text节中的偏移量0处,即0x0040_1000。
symbol
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)告诉它的类型是 Program Counter relative 32bit field relocation in
.textsection at offset 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>
它获取目标符号
arrVA 0x0040_2000,减去字段偏移量0x0040_100d,加上加数0x18,然后将结果0x100B添加到编译器发出到指令体的任何内容(值0x0000000)。
CPU将把mov 0x0(%rip),%eax语句视为b: 8b 05 0b 10 00 00,正如您在调试器中看到的那样。此指令的RIP为0x0040_1011,当您将32位imm值0x100b添加到RIP时,将从VA 0x0040_201c加载寄存器EAX,VA 0x0040_201c是
arr**的第7个DWORD。
1.什么是sym重定位表中的值是否表示?
为了方便起见,这是通过 readelf 从目标值+加数计算出来的信息,实际上它只是间接地作为Rela.Info的高dword包含在重定位记录中。以序数的形式转化为符号表。

相关问题