我熟悉这种形式的记忆参考:
XXX ptr [base + index * size + displacement]
其中XXX是某种大小(字节/字/双字/等),base
和index
都是寄存器,size
是2的小幂,{{1}是签名值。
amd64引入了rip-relative寻址。据我了解,我应该可以使用displacement
作为基址寄存器。但是,当我用clang-900.0.39.2尝试这个时:
rip
我明白了:
错误:无效的基数+索引表达式
mov r8b, byte ptr [rip + rdi * 1 + Lsomething]
使用mov r8b, byte ptr [rip + rdi * 1 + Lsomething]
作为基址寄存器时,是否无法使用索引寄存器?我是否必须使用rip
来计算lea
然后偏移到那个?
答案 0 :(得分:3)
不,[RIP + rel32]
是涉及RIP的唯一寻址模式。另请参阅Referencing the contents of a memory location. (x86 addressing modes)。
如果要为静态数组建立索引的最高效率,则需要创建与位置相关的代码,以便在正常寻址模式下将表地址用作32位绝对disp32
。在Linux中允许这种位置依赖的可执行文件,但不允许共享库(必须是PIC)。默认配置gcc以制作PIE时,请参阅32-bit absolute addresses no longer allowed in x86-64 Linux?了解如何使用-fno-pie -no-pie
。
它不是" RIP作为基址寄存器"在任意寻址模式下;机器码编码没有空间。 x86-64有16个可能的基址寄存器,在ModR / M或SIB字节中编码3位,在可选REX前缀中编码1位。使RIP可用作任意寻址模式的基础可能需要突破其他寄存器,并在32位和64位模式之间的有效地址解码中产生许多差异。
x86-32有2种冗余方式来编码[0x123456]
,即无基数+ disp32:有或没有SIB字节,因为SIB具有无基数和无索引的编码。有关漂亮的表格,请参阅http://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing,或参阅英特尔手册。
无索引SIB编码可以编码[esp]
而不是[esp+esp]
,因为ModR / M编码意味着base = RSP是转义代码,意味着"那里& #39; sa 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相对地址。