对我来说,这就像一部时髦的电影。它的用途是什么?我应该什么时候使用它?


当前回答

LEA指令可用于避免CPU对有效地址进行耗时的计算。如果地址被重复使用,则将其存储在寄存器中而不是每次使用时计算有效地址更有效。

其他回答

如果有人已经提到了,请原谅我,但如果有人想知道x86糟糕的旧时代,内存分割仍然是相关的:您将始终从以下两条指令中得到相同的结果:

LEA AX, DS:[0x1234]

and

LEA AX, CS:[0x1234]

“有效地址”只是seg:off逻辑地址的偏移部分。在本例中,0x1234。

LEA不添加段基础。这将击败最初的一个用例,即进行地址计算以获得指针(偏移量),实际上可以取消引用。例如lea bx,[array+si]。如果添加了DS基以给出线性地址,则稍后的mov ax,[bx]将再次添加DS基。此外,20位结果通常不适合16位寄存器。

看见https://www.stevemorse.org/8086/index.html8086的建筑师写了一本关于指令集的书,现在在他的网站上免费。关于LEA的部分提到了他的一些设计意图。

LEA:只是一个“算术”指令。。

MOV在操作数之间传输数据,但lea只是在计算

在MOV上使用LEA的最大原因是,如果需要对用于计算地址的寄存器执行算术运算。实际上,您可以在几个寄存器上组合有效地“免费”执行相当于指针运算的操作

真正令人困惑的是,您通常会像MOV一样编写LEA,但实际上并没有取消对内存的引用。换句话说:

移动EAX,[ESP+4]

这将把ESP+4点的内容移动到EAX中。

LEA-EAX,[EBX*8]

这将把有效地址EBX*8移动到EAX,而不是在该位置找到的地址。正如您所看到的,当MOV仅限于加法/减法时,也可以乘以2的因子(缩放)。

LEA(Load Effective Address,加载有效地址)指令是获取任何英特尔处理器内存寻址模式产生的地址的一种方法。

也就是说,如果我们有这样的数据移动:

MOV EAX, <MEM-OPERAND>

它将指定存储位置的内容移动到目标寄存器中。

如果我们用LEA替换MOV,那么内存位置的地址将通过<MEM-OPERAND>寻址表达式以完全相同的方式计算。但是,我们将位置本身带入目的地,而不是存储位置的内容。

LEA不是特定的算术指令;这是一种拦截由处理器的任何一种存储器寻址模式产生的有效地址的方法。

例如,我们可以在一个简单的直接地址上使用LEA。完全不涉及算术:

MOV EAX, GLOBALVAR   ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR   ; fetch the address of GLOBALVAR into EAX.

这是有效的;我们可以在Linux提示符下测试它:

$ as
LEA 0, %eax
$ objdump -d a.out

a.out:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   8d 04 25 00 00 00 00    lea    0x0,%eax

这里,没有添加缩放值,也没有偏移。零移动到EAX。我们也可以使用带立即数的MOV来实现这一点。

这就是为什么认为LEA中括号是多余的人被严重误解的原因;括号不是LEA语法,而是寻址模式的一部分。

LEA在硬件级别是真实的。生成的指令对实际寻址模式进行编码,并且处理器将其执行到计算地址的点。然后它将该地址移动到目的地,而不是生成内存引用。(由于任何其他指令中寻址模式的地址计算对CPU标志没有影响,LEA对CPU标志也没有影响。)

与从地址0加载值相比:

$ as
movl 0, %eax
$ objdump -d a.out | grep mov
   0:   8b 04 25 00 00 00 00    mov    0x0,%eax

这是一个非常相似的编码,看到了吗?只有LEA的8d已更改为8b。

当然,这种LEA编码比将立即零移动到EAX要长:

$ as
movl $0, %eax
$ objdump -d a.out | grep mov
   0:   b8 00 00 00 00          mov    $0x0,%eax

执法机关没有理由排除这种可能性,尽管只是因为有一个更短的替代方案;它只是以正交的方式与可用的寻址模式相结合。

也许只是LEA指令的另一件事。您还可以使用LEA将寄存器快速乘以3、5或9。

LEA EAX, [EAX * 2 + EAX]   ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX]   ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX]   ;EAX = EAX * 9