rip 可以与另一个具有 RIP 相对寻址的寄存器一起使用吗?
Can rip be used with another register with RIP-relative addressing?
我熟悉这种形式的内存引用:
XXX ptr [base + index * size + displacement]
其中XXX是某个大小(byte/word/dword/etc),base
和index
都是寄存器,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 相对地址。
我熟悉这种形式的内存引用:
XXX ptr [base + index * size + displacement]
其中XXX是某个大小(byte/word/dword/etc),base
和index
都是寄存器,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 相对地址。