对我来说,这就像一部时髦的电影。它的用途是什么?我应该什么时候使用它?
当前回答
尽管有各种解释,LEA是一种算术运算:
LEA Rt, [Rs1+a*Rs2+b] => Rt = Rs1 + a*Rs2 + b
只是它的名字对于shift+add操作来说非常愚蠢。其原因已经在最高评级的答案中解释过(即,它是为了直接映射高级内存引用而设计的)。
其他回答
尽管有各种解释,LEA是一种算术运算:
LEA Rt, [Rs1+a*Rs2+b] => Rt = Rs1 + a*Rs2 + b
只是它的名字对于shift+add操作来说非常愚蠢。其原因已经在最高评级的答案中解释过(即,它是为了直接映射高级内存引用而设计的)。
LEA指令的另一个重要特征是它不会改变条件代码(如CF和ZF),而通过ADD或MUL等算术指令计算地址则会改变。这一特性降低了指令之间的依赖程度,从而为编译器或硬件调度器的进一步优化腾出了空间。
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 ebx, [ebx+eax*8]
用一条指令进一步移动ebx指针eax项(在64位/元素数组中)。基本上,您可以从x86体系结构支持的复杂寻址模式中受益,从而有效地操作指针。
如果有人已经提到了,请原谅我,但如果有人想知道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的部分提到了他的一些设计意图。
推荐文章
- ARM架构与x86有何不同?
- 为什么GCC在实现整数除法时使用奇数乘法?
- 基指针和堆栈指针到底是什么?他们指的是什么?
- 汇编代码vs机器代码vs目标代码?
- 什么是回跳线?它是如何工作的?
- 提交到App Store的问题:不支持架构x86
- “switch”比“if”快吗?
- 为什么Java在连续整数上的切换与添加的情况下运行得更快?
- 多核汇编语言是什么样子的?
- 如何在没有操作系统的情况下运行程序?
- 是否可以“反编译”Windows .exe?或者至少看看大会?
- 使用GCC产生可读的程序集?
- 如何用SSE4.2和AVX指令编译Tensorflow ?
- 为什么这段代码在对循环携带的加法进行强度降低的乘法运算后执行得更慢?
- 在Intel sandybridge系列cpu中对管道的程序进行反优化