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

Can rip be used with another register with RIP-relative addressing?

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

XXX ptr [base + index * size + displacement]

其中XXX是某个大小(byte/word/dword/etc),baseindex都是寄存器,size是2的小幂,displacement 是一个带符号的值。

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

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

我得到:

error: invalid base+index expression

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

使用rip作为基址寄存器是不是不能使用变址寄存器?我必须使用 lea 来计算 rip + Lsomething 然后偏移到那个吗?

不,[RIP + rel32] 是唯一涉及 RIP 的寻址模式。 另请参阅

如果您希望索引静态数组的效率最高,您需要编写位置相关的代码,以便您可以在正常寻址中将 table 地址用作 32 位绝对地址 disp32模式。这在位置相关的 executable 中的 Linux 中是允许的,但共享库(必须是 PIC)不允许。请参阅 32-bit absolute addresses no longer allowed in x86-64 Linux? 以了解如何使用 -fno-pie -no-pie 当 gcc 默认配置为制作 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 有一种针对 no-base 和 no-index 的编码。请参阅 http://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing 以获得更好的 table,或参阅 Intel 的手册。

无索引 SIB 编码使得编码 [esp] 而不是 [esp+esp] 成为可能,因为 ModR/M 编码表示 base=RSP 是表示“有一个 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 相对地址。