leaq的第一个操作数必须是一个内存地址,第二个操作数必须是一个寄存器吗?

时间:2018-10-25 22:09:06

标签: assembly x86 att

在ATT汇编语言中,使用leaq指令时,其第一个操作数必须是内存地址,而不是寄存器或常量(前缀$)吗?它的第二个操作数必须是一个寄存器吗?通过阅读《计算机系统:程序员的观点》,我得到了这种印象,并且从未见过与我的猜测不同的示例。谢谢。

2 个答案:

答案 0 :(得分:2)

是的,这是正确的。虽然可以从技术上对具有两个寄存器操作数的lea进行编码,但是这种编码无效,并导致#UD异常。有关详细信息,请参见this referencethis one

答案 1 :(得分:1)

即使它是可编码的,您也永远不想使用它。

如果要在寄存器中放入常量,则永远不要使用leamov $1234, %eaxlea 1234, %eax(disp32寻址模式中的绝对地址)更短,效率更高。

静态地址LEA的唯一用例是具有RIP相对寻址模式的64位代码,例如lea symbol(%rip), %rax(7个字节),而mov $symbol, %eax(5个字节)不是之所以可用,是因为您需要与位置无关的代码,并且/或者该地址不适合32位零扩展立即数。

有关mov $symbol, %rdi不是最佳选择的信息,请参见Difference between movq and movabsq in x86-64


在32位代码中,lea symbol, %edi是6个字节(操作码+ modrm + disp32),并且仅在Intel Sandybridge系列CPU上运行一个端口1或端口5。 (https://agner.org/optimize/

mov $symbol, %edi是5个字节(opcode + imm32 short form with no ModRM byte),可以在任何ALU端口上运行。

与16位代码相同:mov $symbol, %di是3个字节,而lea symbol, %di是4个字节,具有相同的执行端口差异。 (或者使用NASM语法,lea di, [symbol]mov di, symbol,或GAS mov di, OFFSET symbol或MASM中的.intel_syntax。)


但是,

LEA在base = register寻址模式下很有用。如果地址适合32位符号扩展的disp32,则类似于lea symbol(%rdi), %rax

或者对于任意的移位和加法用法,例如lea 123(%rdi, %rdi, 2), %eaxeax = 3*edi + 123Using LEA on values that aren't addresses / pointers?