[英]Can rip be used with another register with RIP-relative addressing?
我熟悉这种形式的内存引用:
XXX ptr [base + index * size + displacement]
其中 XXX 是某个大小(字节/字/双字/等), base
和index
都是寄存器, 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]
寻址模式,或任何其他替代方法。 ( 非索引寻址模式有时会在 Intel 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 将[disp32]
的较短(无 SIB)编码重新用于[RIP + disp32]
,也称为[RIP + rel32]
。
32 位绝对地址 ( [disp32]
) 仍然可以使用更长的 SIB 编码进行编码。 (这是 NASM 默认情况下所做的,如果您不使用default rel
。)甚至没有[RIP + disp8]
(例如用于加载附近的代码地址)。 ModR/M 字节的 Mod 和 M 字段中恰好有一个位模式,用于编码 RIP 相对地址。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.