我熟悉这种形式的内存引用:
XXX ptr [base + index * size + displacement]
其中XXX是某种大小(字节/字/双字等),
base
和index
都是寄存器,size
是2的小数幂,displacement
是有符号值。amd64引入了rip-relative寻址。据我了解,我应该能够将
rip
用作基址寄存器。但是,当我尝试使用clang-900.0.39.2时:mov r8b, byte ptr [rip + rdi * 1 + Lsomething]
我得到:
将
rip
用作基址寄存器时,是否不可能使用索引寄存器?我必须使用lea
来计算rip + Lsomething
,然后将其偏移吗? 最佳答案
不,[RIP + rel32]
是唯一涉及RIP的寻址模式。 另请参阅Referencing the contents of a memory location. (x86 addressing modes)。
如果要最大效率地索引静态数组,则需要制作与位置有关的代码,以便可以在正常寻址模式下将表地址用作32位绝对disp32
。在Linux中,位置相关的可执行文件允许这样做,但共享库(必须是PIC)不允许这样做。有关在默认情况下将gcc配置为生成PIE的方式,如何使用-fno-pie -no-pie
的信息,请参见32-bit absolute addresses no longer allowed in x86-64 Linux?。
否则,对于与位置无关的数组索引,请使用,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或SIB字节中的3位+可选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或参阅英特尔手册。
无索引的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]
。
仍可以使用较长的SIB编码来编码32位绝对地址([disp32]
)。 (如果您不使用default rel
,这是NASM的默认设置。)甚至没有[RIP + disp8]
(例如,用于加载附近的代码地址)。在ModR/M字节的Mod和M字段中,只有一个位模式可以对RIP相对地址进行编码。
关于assembly - rip是否可以与具有RIP相对寻址的另一个寄存器一起使用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48124293/