ar db "Defference $"
有什么区别
mov dx,offset ar
和
lea dx,ar
我认为两者都在做相同的工作,但这两者有什么区别
在此用例中,LEA 和 MOV 执行相同的操作。如果你想以更复杂的方式计算地址,LEA 比 MOV 更强大。
举例来说,假设您想要获取数组中第 n 个字符的地址,并且 n 存储在 bx 中。使用 MOV,您必须编写以下两条指令:
Mov dx, offset ar
add dx, bx
有了 lea,您只需一个指令即可完成:
lea dx, [ar + bx]
这里要考虑的另一件事:
add dx,bx
指令将更改CPU的状态标志。另一方面,在 lea dx, [ar + bx]
指令内完成的加法不会以任何方式更改标志,因为它不被视为算术指令。
如果您想在进行一些简单计算时保留标志(地址计算非常常见),这有时会很有帮助。存储和恢复标志寄存器是可行的,但操作很慢。
引自 x86 处理器的汇编语言,7e,KIP R. IRVINE
无法使用 OFFSET 来获取堆栈参数的地址,因为 OFFSET 仅适用于编译时已知的地址。以下语句无法汇编:
mov esi,OFFSET [ebp-30] ; error
在汇编代码中使用 OFFSET 取决于您的编译器,因为这是一条仅在编译期间使用的指令。 (并非所有汇编器都使用它)
编译器将知道数据的地址,因为它将是要使用的常量地址。生成的代码将用一个数字代替您的常量。例如,如果发现
MYVAR
占据了0x1234的(相对)地址,那么在编译时
MOV AX, _MYVAR
将成为
MOVE AX, 1234
另一方面,LEA 是仅由机器执行的机器代码。它通常用于访问函数堆栈上的局部变量(数组),因为 BP 会根据您调用函数的位置而变化。
LEA AX, -5[BP]
您可以使用它们来做同样的事情,但是,如果地址有点复杂,
LEA
总是会更好。
考虑您有以下字符数组:
ASC_TBL DB '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
如果你想获取第 6 个元素“5”,你可以使用
offset
: 执行类似的操作
mov ax, offset ASC_TBL
add ax, 5h; flags [PF] will be affected
另一方面,如果您使用
LEA
指令,您可以简单地使用 one 指令,如下所示:
LEA ax, [ASC_TBL + 5h]; no flags are affected
请注意:
虽然使用
LEA
证明它比使用offset
有优势,但如果地址写起来不是很复杂或者两者都会用相同的数字做同样的事情,那么使用offset
会更有效的指令。
原因是 offset ASC_TBL
是在翻译过程中计算的 - 就像被预处理一样 - 但是,LEA
是实际的处理器指令。
不能使用
offset
指令来获取编译前未知的地址。