RIP 可以与另一个具有RIP相对寻址的寄存器一起使用吗?



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

XXX ptr [base + index * size + displacement]

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

AMD64引入了RIP相对寻址。据我了解,我应该能够使用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 + rel32]是唯一涉及 RIP 的寻址模式。另请参阅引用内存位置的内容。(x86 寻址模式)。

如果要最大程度地提高为静态数组编制索引的效率,则需要创建与位置相关的代码,以便在正常寻址模式下将表地址用作 32 位绝对disp32。 在 Linux 中,在位置相关的可执行文件中允许这样做,但不允许共享库(必须是 PIC)。 看到 x86-64 Linux 中不再允许使用 32 位绝对地址?了解如何在默认情况下配置 GCC 以制作 PIE 时使用-fno-pie -no-pie

否则,对于与位置无关的数组索引,lea rsi, [rip + Lsomething]并使用指针增量或[rsi + rdi*1 + constant]寻址模式,或任何其他可行的替代方法。 (非索引寻址模式有时会在英特尔 CPU 上节省 uop,因此指针增量可能很好,尤其是在展开时,因此每个指针的add可以收回成本,而不是对多个数组使用相同的索引。


在任意寻址模式下,它不是"RIP 作为基本寄存器";机器代码编码中没有空间。 x86-64 有 16 个可能的基本寄存器,用 ModR/M 或 SIB 字节中的 3 位 + 可选 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将较短的(无SIB)编码重新用于[disp32][RIP + disp32],即[RIP + rel32]

32位绝对地址([disp32])仍然可以用更长的SIB编码进行编码。 (这是 NASM 默认执行的操作,如果您不使用default rel.) 甚至没有[RIP + disp8](例如,用于加载附近的代码地址)。 在 ModR/M 字节的 Mod 和 M 字段中只有一个位模式,用于编码 RIP 相对地址。

最新更新