【问题标题】:Can rip be used with another register with RIP-relative addressing?rip 可以与另一个具有 RIP 相对寻址的寄存器一起使用吗?
【发布时间】:2018-06-15 21:31:42
【问题描述】:

我熟悉这种形式的内存引用:

XXX ptr [base + index * size + displacement]

其中 XXX 是某种大小(字节/字/双字/等),baseindex 都是寄存器,size 是 2 的小幂,displacement 是有符号值。

amd64 引入了 rip-relative 寻址。据我了解,我应该能够使用rip 作为基址寄存器。但是,当我尝试使用 clang-900.0.39.2 时:

mov r8b, byte ptr [rip + rdi * 1 + Lsomething]

我明白了:

错误:无效的基数+索引表达式

mov r8b, byte ptr [rip + rdi * 1 + Lsomething]

使用rip作为基址寄存器时是不是不能使用变址寄存器?我是否必须使用lea 来计算rip + Lsomething,然后抵消掉?

【问题讨论】:

  • RIP + 置换是 RIP 相对寻址唯一允许的寻址。因此,您可以使用 lea 获取 [rip + Lsomething] 并将其放在通用寄存器中。该寄存器可用于完成其余的地址计算。没有真正的办法绕过这个限制。
  • 您可以在Intel® 64 and IA-32 Architectures Software Developer’s Manual 部分2.2.1.6 RIP-Relative Addressing 中找到它
  • 仅供参考,您可能想要movzx r8d, byte ptr [ ...],除非您特别想要合并到 R8 的现有内容而不是启动新的依赖链为那个寄存器。
  • @PeterCordes,感谢您的建议。我正在编写一个玩具 Meltdown PoC,这是探针负载,因此大小或目的地无关紧要。

标签: assembly x86-64 addressing-mode


【解决方案1】:

不,[RIP + rel32] 是唯一涉及 RIP 的寻址模式。 另请参阅 Referencing the contents of a memory location. (x86 addressing modes)

如果您想要最大效率地索引静态数组,则需要编写位置相关代码,以便可以在正常寻址模式下将表地址用作 32 位绝对地址disp32。在 Linux 中,位置相关的可执行文件中允许这样做,但共享库(必须是 PIC)中不允许这样做。当 gcc 默认配置为制作 PIE 时,请参阅 32-bit absolute addresses no longer allowed in x86-64 Linux? 了解如何使用 -fno-pie -no-pie

否则对于位置无关的数组索引,lea rsi, [rip + Lsomething] 并使用指针增量或[rsi + rdi*1 + constant] 寻址模式,或任何其他替代方法。 (Non-indexed addressing modes sometimes save a uop on Intel CPUs 所以指针增量可能很好,特别是如果你正在展开,所以每个指针的 add 可以为自己付出更多,而不是为多个数组使用相同的索引。)


在任意寻址模式下,它不是“RIP 作为基址寄存器”; 机器码编码中没有空间。 x86-64 有 16 个可能的基址寄存器,用 ModR/M 中的 3 位或 SIB 字节 + 可选 REX 前缀中的 1 位编码。要使 RIP 可用作具有任意寻址模式的基础,则需要消除一些其他寄存器,并在 32 位和 64 位模式之间的有效地址解码方面产生很多差异。

x86-32 有 2 种冗余方式来编码 [0x123456],即 no-base + disp32:有或没有 SIB 字节,因为 SIB 有无基数和无索引的编码。请参阅http://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing 以获得漂亮的表格,或参阅英特尔的手册。

无索引 SIB 编码可以编码 [esp] 而不是 [esp+esp],因为表示 base=RSP 的 ModR/M 编码是表示“有一个 SIB”的转义码。他们本可以设计它,以便您可以使用esp 作为除esp 以外的碱基的索引,但首先没有人愿意使用esp 作为索引。有趣的事实:无基(disp32)编码使用了没有位移的[ebp],这就是为什么[ebp]实际上被编码为[ebp + disp8=0]。在 x86-64 模式下,这也适用于 R13。

x86-64 将 [disp32] 的较短(无 SIB)编码重新用于 [RIP + disp32],即 [RIP + rel32]

32 位绝对地址 ([disp32]) 仍可使用较长的 SIB 编码进行编码。 (如果你不使用default rel,这是 NASM 默认所做的。)甚至没有[RIP + disp8](例如,用于加载附近的代码地址)。 ModR/M 字节的 Mod 和 M 字段中恰好有一个位模式,用于编码 RIP 相对地址。

【讨论】:

  • 感谢您的详细解答!让我弄清楚I had to fix the SIB disp32-only encoding。公平地说,我在generalised the index=4 special case 仅支持 SIB=24h (S=0 I=4 B=4) 时引入了该错误,但没有意识到 mod=0 index=4 base=5 是两种特殊情况.这提醒了我,您的文本并不完全准确:由于忽略了 S(比例)字段,SIB disp32-only 编码实际上可以用 4 种不同的方式编码,S 等于 0、1、2 或 3。
  • @ecm:有趣的一点!如果有可能有用的话,会有一些新的寻址模式的空间。但是没有涉及寄存器号的干净方法,所以就作为一个好的编译器目标而言,我可以理解为什么他们不会打扰。塞进几个寄存器的有限选择只会让解码很痛苦,而且我认为仅使用 32 位常量和 RIP 与否没有什么值得做的。通过添加或减去(或缩放)32 位数字来扩大范围并不值得。
猜你喜欢
  • 2021-06-11
  • 2021-08-17
  • 2015-09-22
  • 2017-04-03
  • 1970-01-01
  • 2012-09-02
  • 2018-04-07
  • 1970-01-01
相关资源
最近更新 更多