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 使用子程序