【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
对我来说,这就像一部时髦的MOV。 它的目的是什么?何时使用?
#1楼
8086具有大量的指令集,它们接受寄存器操作数和有效地址,执行一些计算以计算该有效地址的偏移量部分,并执行一些涉及寄存器和所计算地址所指向的存储器的操作。 让该系列中的指令之一按上述方式操作非常简单,只是跳过了实际的内存操作。 这个,说明:
mov ax,[bx+si+5]
lea ax,[bx+si+5]
在内部几乎完全相同。 区别是跳过的步骤。 两种指令的工作方式如下:
temp = fetched immediate operand (5)
temp += bx
temp += si
address_out = temp (skipped for LEA)
trigger 16-bit read (skipped for LEA)
temp = data_in (skipped for LEA)
ax = temp
至于为什么英特尔认为该指令值得包括在内,我不确定,但是实施起来便宜的事实将是一个很大的因素。 另一个因素可能是英特尔的汇编器允许相对于BP寄存器定义符号的事实。 如果将fnord
定义为BP相对符号(例如BP + 8),则可以说:
mov ax,fnord ; Equivalent to "mov ax,[BP+8]"
如果要使用诸如stosw之类的数据将数据存储到BP相对地址,则可以说
mov ax,0 ; Data to store
mov cx,16 ; Number of words
lea di,fnord
rep movs fnord ; Address is ignored EXCEPT to note that it's an SS-relative word ptr
比:
mov ax,0 ; Data to store
mov cx,16 ; Number of words
mov di,bp
add di,offset fnord (i.e. 8)
rep movs fnord ; Address is ignored EXCEPT to note that it's an SS-relative word ptr
请注意,忘记世界“偏移”将导致位置[BP + 8]的内容而不是值8的内容被添加到DI。 哎呀。
#2楼
LEA
指令的另一个重要特征是,它不会更改条件代码(例如CF
和ZF
,而通过算术指令(例如ADD
或MUL
计算地址。 该功能降低了指令之间的依赖性,从而为编译器或硬件调度程序的进一步优化留出了空间。
#3楼
lea
是“加载有效地址”的缩写。 它将源操作数将位置引用的地址加载到目标操作数。 例如,您可以使用它来:
lea ebx, [ebx+eax*8]
使用单个指令将ebx
指针eax
项进一步移动(在64位/元素数组中)。 基本上,您将从x86架构支持的复杂寻址模式中受益,可以有效地操作指针。
#4楼
摘自Abrash的“汇编禅” :
LEA
,这是唯一执行内存寻址计算但实际上并未寻址内存的指令。LEA
接受标准的内存寻址操作数,但只不过将计算出的内存偏移量存储在指定的寄存器中即可,该寄存器可以是任何通用寄存器。这给了我们什么?
ADD
不提供的两件事:
- 使用两个或三个操作数执行加法的能力,以及
- 将结果存储在任何寄存器中的能力; 不只是源操作数之一。
LEA
不会更改标志。
例子
-
LEA EAX, [ EAX + EBX + 1234567 ]
计算EAX + EBX + 1234567
(这是三个操作数) -
LEA EAX, [ EBX + ECX ]
计算EBX + ECX
而不会覆盖任何结果。 - 如果您像
LEA EAX, [ EBX + N * EBX ]
这样使用它,则乘以常数(乘以2、3、5或9)LEA EAX, [ EBX + N * EBX ]
(N可以是1,2,4,8)。
其他用例在循环中很方便: LEA EAX, [ EAX + 1 ]
和INC EAX
之间的区别在于,后者更改了EFLAGS
而前者则没有改变; 这保留了CMP
状态。
#5楼
也许关于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
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3151019