在ATT汇编语言中,使用leaq指令时,其第一个操作数必须是内存地址,而不是寄存器或常量(前缀$
)吗?它的第二个操作数必须是一个寄存器吗?通过阅读《计算机系统:程序员的观点》,我得到了这种印象,并且从未见过与我的猜测不同的示例。谢谢。
答案 0 :(得分:2)
是的,这是正确的。虽然可以从技术上对具有两个寄存器操作数的lea
进行编码,但是这种编码无效,并导致#UD
异常。有关详细信息,请参见this reference或this one。
答案 1 :(得分:1)
即使它是可编码的,您也永远不想使用它。
如果要在寄存器中放入常量,则永远不要使用lea
。 mov $1234, %eax
比lea 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), %eax
做eax = 3*edi + 123
。 Using LEA on values that aren't addresses / pointers?