需要正确理解LEA指令的功能。
该指令有两个操作数。左边是目的操作数,表示操作结果保存在此,该指令目的操作数只能是8个通用寄存器之一。逗号右边的是源操作数,该指令的源操作数只能是一个存储单元,表达存储单元有多种寻址方式。
LEA指令的功能是将源操作数、即存储单元的有效地址(偏移地址)传送到目的操作数。
示例指令中,[BX+SI+0F54H]采用相对基址变址的寻址方式表达存储单元,它表示的存储单元的有效地址是:BX内容加SI内容加0F54H。这个结果被传送到BX中。
是否是很烦琐?
该指令涉及了多个基本知识点,尤其是存储器寻址方式。问题很有可能是前面的内容并没有真正理解和掌握。
这是汇编语言程序设计课程的一个特点,知识点点滴滴,需要静心学习。
--------------------------------------------
这个指令一般用于加法或者乘法的优化,以获得更高的运行效率
这个指令是用来取EA地址的,一般情况是可以和MOV AX,OFFSET BUFFER等效,但是还是有区别的:1,运行一条LEA大约是100条OFFSET指令的时间,2,OFFSET不可以用于相对基址变址这样的复杂寻址方式
offset属伪指令范畴,是在汇编时处理的,对地址不变的变量可以取其有效地址。如楼上的“MOV DX,OFFSET A”
但是,如果地址是变量(也就是指针),其有效地址是随程序运行而变化的,offset是肯定无法取其有效地址的。因为“伪指令”不可能在程序运行时起作用。例如,“MOV DX,OFFSET 1234[SI+BX]”肯定是不行的。
LEA是指令,可以在地址是变量(也就是指针)的情况下,取其有效地址。
例如,“LEA DX,1234[SI+BX]”肯定是可以的。因此,它从来就不是多余的。
------------------------------------------
堆栈种分配的局部变量所谓的“标号”,你以为是什么?(都是那些该死的宏惹的祸,大家要都是老老实实写代码,就不会有这些疑问了)。
比如你用local在栈上定义了一个局部变量LocalVar,你知道实际的指令是什么么?一般都差不多像下面的样子:
push ebp
mov esp, ebp
sub esp, 4
现在栈上就有了4各字节的空间,这就是你的局部变量。
接下来,你执行mov LocalVar, 4,那么实际的指令又是什么?是这样:
mov dword ptr [ebp-4], 4
于是,这个局部变量的“地址”就是ebp-4——显然,它不是一个固定的地址。现在需要将它的“地址”作为参数传给某个函数,你这样写:
invoke/call SomeFunc, addr LocalVar
实际生成的指令是:
lea eax, [ebp-4]
push eax
call SomeFunc
当然,你也可以写成:
mov eax, ebp
sub eax, 4
push eax
call SomeFunc
看到了,这里多了一条指令。这就是lea的好处。于是,lea又多了一个非常美妙的用途:作简单的算术计算,特别是有了32位指令的增强寻址方式,更是“如虎添翼”:
比如你要算EAX*4+EBX+3,结果放入EDX,怎么办?
mov edx, eax
shl edx, 2
add edx, ebx
add edx, 3
现在用lea一条指令搞定:
lea edx, [ebx+eax*4+3]