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

XXX ptr [base + index * size + displacement]

其中XXX是某种大小(字节/字/双字等),baseindex都是寄存器,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/

10-09 10:18