对我来说,这就像一部时髦的电影。它的用途是什么?我应该什么时候使用它?
当前回答
如果有人已经提到了,请原谅我,但如果有人想知道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的部分提到了他的一些设计意图。
其他回答
在MOV上使用LEA的最大原因是,如果需要对用于计算地址的寄存器执行算术运算。实际上,您可以在几个寄存器上组合有效地“免费”执行相当于指针运算的操作
真正令人困惑的是,您通常会像MOV一样编写LEA,但实际上并没有取消对内存的引用。换句话说:
移动EAX,[ESP+4]
这将把ESP+4点的内容移动到EAX中。
LEA-EAX,[EBX*8]
这将把有效地址EBX*8移动到EAX,而不是在该位置找到的地址。正如您所看到的,当MOV仅限于加法/减法时,也可以乘以2的因子(缩放)。
也许只是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
这里有一个例子。
// compute parity of permutation from lexicographic index
int parity (int p)
{
assert (p >= 0);
int r = p, k = 1, d = 2;
while (p >= k) {
p /= d;
d += (k << 2) + 6; // only one lea instruction
k += 2;
r ^= p;
}
return r & 1;
}
使用-O(optimize)作为编译器选项,gcc将找到指定代码行的lea指令。
正如前面提到的现有答案,LEA具有执行内存寻址运算而不访问内存的优点,将运算结果保存到不同的寄存器,而不是简单形式的加法指令。真正的潜在性能优势是现代处理器有一个单独的LEA ALU单元和端口,用于有效的地址生成(包括LEA和其他内存参考地址),这意味着LEA中的算术运算和ALU中的其他正常算术运算可以在一个核中并行完成。
查看Haswell架构的这篇文章,了解LEA单元的一些详细信息:http://www.realworldtech.com/haswell-cpu/4/
其他答案中未提及的另一个重要点是LEA REG,[MemoryAddress]指令是PIC(位置无关代码),它将此指令中的PC相对地址编码为参考MemoryAddress。这不同于MOV REG,MemoryAddress编码相对虚拟地址,需要在现代操作系统中重新定位/修补(如ASLR是常见功能)。因此,LEA可用于将非PIC转换为PIC。
所有正常的“计算”指令,如加法、异或设置状态标志,如零、符号。如果使用复杂的地址AX-xor:=mem[0x33+BX+8*CX],则标志将根据xor操作设置。
现在您可能需要多次使用该地址。将这样的地址加载到寄存器中并不是为了设置状态标志,幸运的是,它并没有。短语“加载有效地址”使程序员意识到这一点。这就是奇怪表情的由来。
很明显,一旦处理器能够使用复杂的地址来处理其内容,它就能够将其计算用于其他目的。实际上,它可以用于在一条指令中执行转换x<-3*x+1。这是汇编程序设计中的一条一般规则:无论它如何摇晃你的船,都要使用指令。唯一重要的是指令所体现的特定转换是否对您有用。
要旨
MOV, X| T| AX'| R| BX|
and
LEA, AX'| [BX]
对AX具有相同的影响,但对状态标志没有影响。(这是ciasdis符号。)
推荐文章
- 测试点%eax %eax
- Trap和中断的区别是什么?
- 为什么程序不是经常用汇编编写的?
- 保护可执行文件不受逆向工程的影响?
- “每个程序员应该知道的关于内存的事情”有多少仍然是有效的?
- 在GDB中显示当前的组装指令
- 为什么引入无用的MOV指令会加速x86_64汇编中的紧循环?
- ARM架构与x86有何不同?
- 为什么GCC在实现整数除法时使用奇数乘法?
- 基指针和堆栈指针到底是什么?他们指的是什么?
- 汇编代码vs机器代码vs目标代码?
- 什么是回跳线?它是如何工作的?
- 提交到App Store的问题:不支持架构x86
- “switch”比“if”快吗?
- 为什么Java在连续整数上的切换与添加的情况下运行得更快?