WIN32汇编语言教程:第03章 使用MASM · 3.3 标号、变量和数据结构(5)

3. 获取变量地址

获取变量地址的操作对于全局变量和局部变量是不同的。

对于全局变量,它的地址在编译的时候已经由编译器确定了,它的用法大家都不陌生:

mov    寄存器,offset 变量名

其中offset是取变量地址的伪操作符,和sizeof伪操作符一样,它仅把变量的地址代到指令中去,这个操作是在编译时而不是在运行时完成的。

对于局部变量,它是用ebp来做指针操作的,假设ebp的值是40100h,那么局部变量1的地址是ebp-4即400FCh,由于ebp的值随着程序的执行环境不同可能是不同的,所以局部变量的地址值在编译的时候也是不确定的,不可能用offset伪操作符来获取它的地址。

80386处理器中有一条指令用来取指针的地址,就是lea指令,如:

lea    eax,[ebp-4]

该指令可以在运行时按照ebp的值实际计算出地址放到eax中。

如果要在invoke伪指令的参数中用到一个局部变量的地址,该怎么办呢?参数中是不可能写入lea指令的,用offset又是不对的。MASM对此有一个专用的伪操作符addr,其格式为:

addr 局部变量名和全局变量名

当addr后跟全局变量名的时候,用法和offset是相同的;当addr后面跟局部变量名的时候,编译器会自动用lea指令先把地址取到eax中,然后用eax来代替变量地址使用。注意addr伪操作符只能在invoke的参数中使用,不能用在类似于下列的场合:

mov eax,addr 局部变量名  ;注意:错误用法
;假设在一个子程序中有如下invoke指令:
 invoke Test,eax,addr szHello

其中Test是一个需要两个参数的子程序,szHello是一个局部变量,会发生什么结果呢?编译器会把invoke伪指令和addr翻译成下面这个模样:

lea   eax,[ebp-4]
push  eax   ;参数2:addr szHello
push  eax   ;参数1:eax
call  Test

发现了什么?到push第一个参数eax之前,eax的值已经被lea eax,[ebp-4]指令覆盖了!也就是说,要用到的eax的值不再有效,所以,当在invoke中使用addr伪操作符时,注意在它的前面不能用eax,否则eax的值会被覆盖掉,当然eax在addr的后面的参数中用是可以的。幸亏MASM编译器对这种情况有如下错误提示:

error A2133: register value overwritten by INVOKE

否则,不知道又会引出多少莫名其妙的错误!

上页:第03章 使用MASM · 3.3 标号、变量和数据结构(4) 下页:第03章 使用MASM · 3.4 使用子程序

第03章 使用MASM

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号