addr可以处理局部变量而 offset 则不能。局部变量只是在运行时在堆栈中分配内存空间。而 offset 则是在编译时由编译器解释,这显然不能用offset 在运行时来分配内存空间。编译器对 addr 的处理是先检查处理的是全局还是局部变量,若是全局变量则把其地址放到目标文件中,这一点和 offset 相同,若是局部变量,就在执行 invoke 语句前产生如下指令序列:
lea eax, LocalVar
push eax
因为lea指令能够在运行时决定标号的有效地址,所以有了上述指令序列,就可以保证 invoke 的正确执行了。
回复人: cui(蚊子王) (2001-9-2 17:06:36) 得10分
vBin(彬)说的很对,这是用lea(addr事实上就是lea语句)的一个理由;另一个理由是:
假设要bx+10h->bx但又不想影响flag那就只能用lea bx,[bx+10h]了。
回复人: thickhead_cat(笨猫) (2001-9-3 15:39:10) 得10分
我不同意楼上的说法:
其实,
1、汇编里有很多功能,能用不同的指令实现,这一点也不奇怪
2、lea是cpu的指令,而mov ax,offset xxx 只是我们利用编译器的offset自动计算的功能
3、lea指令远在exe文件产生前就有了,那时顶多只有com文件,所以它和执行时计算偏移量无关的!
回复人: totkid(皮耶德) (2001-9-3 16:26:57) 得0分
对不起……我还是有一些不解
局部变量?
如果我要
lea eax,LocalVar
那么我是通过什么寻址方式找到LocalVar的呢???
既然能通过寻址方式找到该变量
为什么不直接把“地址”送到该寄存器呢??
还有……lea指令能够在运行时确定标号的有效地址,请问这是什么意思呢?
我记得标号都是在编译期就被转化为某个确定的偏移了,然后连接时期确定段值
这一切都应该是在运行期之前就确定的东西呀!
还有,关于在堆栈中运行时分配的变量,如果我们为它设定了一个标号,那么我们
要lea它的地址的时候,是怎么知道我们要lea的是某个地址的变量呢?既然我们若
可以指定——“就lea这个变量的地址给我看”,那么我们起码要知道到底是哪个变量,
那么我们到底怎么指定呢??标号是根本不存在于运行时的程序中的,那么我们肯定应该是
指定它的地址了,既然能指定它的地址……那么直接把它的地址发到某个寄存器不就得了?
cui的那个例子使我开了一些窍,不过,难道lea只是用在这些窍门上吗?
我太苯了!不好意思!
回复人: azuo_lee() (2001-9-3 17:16:16) 得15分
堆栈种分配的局部变量所谓的“标号”,你以为是什么?(都是那些该死的宏惹的祸,大家要都是老老实实写代码,就不会有这些疑问了)。
比如你用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]
回复人: CNer(......) (2001-9-3 17:21:26) 得10分
我补充一点:在tasm中,lea指令,很多都是替换成等效的mov offset指令的。
回复人: cui(蚊子王) (2001-9-3 17:34:49) 得15分
关于局部变量我还是举个例子吧:
比如以下的C/C++函数(c调用方式):
void abc(void){
int a=0x1234;
efg(&a);
}
翻译成对等的ASM代码:
_abc proc near
push ebp
mov ebp,esp
sub esp,4h
;
lea eax,[ebp-4h]
mov [eax],1234h
push eax
call _efg
add esp,4h
;
mov esp,ebp
pop ebp
ret
_abc endp
这时栈的情况如下:
---------- <----esp
a
---------- <----ebp
old ebp
----------
ret address
----------
这时要取得a的地址,那只能用"lea eax,[ebp-4h]"而不能用“mov offset...”了。
addr与offset
最新推荐文章于 2024-09-14 12:00:48 发布