Win32汇编_变量
全局变量:
全局变量的作用域是整个程序,Win32汇编的全局变量定义在.data或.data?段内,可以同时定义变量的类型和长度.
格式是:
变量名 类型 初始值1, 初始值2, …
变量名 类型 重复数量 dup (初始值1, 初始值2, …)
例:
.data ;全局变量的类型才可以用缩写
wHour dw ? ;未初始化的word类型变量
wMinute dw 10 ;初始化为10的word类型变量
_hWnd dd ? ;未初始化dword类型的变量
Word_Buffer dw 100 dup (1, 2) ;word类型数组,初始化0001,0002,0001,0002,…
szBuffer Byte 1024 dup (?) ;byte数组,未初始化(未初始化其实就是全0值)
szText db ‘Hello, World!’ ;一个字符串
;在byte类型变量的定义中,可以用引号定义字符串和数值定义的方法混用,假设要定义两个字符串’Hello, World!’和’Hello again’,每个字符串后面跟回车和换行符,最后以一个0字符结尾.
可以如下定义:
szText db ‘Hello, World!’, 0dh, 0ah, ‘Hello again’, 0dh, 0ah, 0
全局变量的定义中既可以指定初值,也可以用问号预留空间,在data?段中,只能用问号预留空间.既然可以用问号预留空间,那么这个未初始化的值是随机的还是确定的.答题是0,所以问号指定的全局变量如果要以0为初始值的话,在程序中可以不必特地为这赋值.
局部变量:
局部变量的作用域是单个子程序,在进入子程序的时候,通过修改栈指针esp来预留出需要的空间,在用ret指令返回主程序之前,同样通过恢复esp丢弃这些空间,这些变量就随之无效了.它的缺点是因为空间是临时分配的,所以无法定义含有初始化值的变量,对局部变量的初始化一般在子程序中同指令完成.
定义格式:
local 变量名1[[重复次数]] [:类型], 变量名2[[重复次数]] [:类型]…
local伪指令必须紧接在子程序定义的伪指令proc后,其他指令开始前.
1: 可以有多个local语句.
2: 不能用类型缩写.
3: 定义结构体,可以用结构体的名称当做类型.
4: 定义dword类型的局部变量,类型可以省略
5: 定义数组时可以用[]括起来.
6: 不能使用定义全局变量的dup伪指令.
7: 不能和已经定义的全局变量重名.
8: 局部变量的起始值是随机的,所以局部变量的值一定要初始化,特别是定义结构体时
例:
Local loc1[1024]: Byte ;1024长的字节数组
Local loc2 ;默认为dword类型的局部变量
Local loc3:WNDCLASS ;一个结构体类型
结构体:
结构体实际是由多个字段组成的数据样板,相当于自己定义的数据类型,结构体中间的每一个字段可以是字节,字,双字,字符串或所有可能的数据类型.
结构体定法如下:
结构名 struct
字段1 类型 ?
字段1 类型 ?
…
结构名 ends
例:
WNDCLASS struct
style DWORD ?
lpfnWndProc DWORD ?
…
WNDCLASS ends
使用结构体在数据段中定义方法如下:
.data?
stWndClass WNDCLASS <> ;未初始化的定义方法
或:
.data
stWndClass WNDCLASS <1, 1> ;定义的同时指定初始值
结构体的引用方法有好几种:
mov eax, stWndClass.lpfnWndProd
在实际使用中,常常有使用指针存取结构体的情况:
mov esi, offset stWndClass
mov eax, [esi + WNDCLASS.lpfnWndProc] ;注意是WNDCLASS. 而不是stWndClass.
如果对一个结构体中的大量字段操作,上一种写法比较烦琐,MASM还有另一种方法,
可以用assume伪指令把寄存器预先定义为结构指针:
mov esi, offset stWndClass
assume esi: ptr WNDCLASS
mov eax, [esi].lpfnWndProc
…
assume esi: nothing ;不再使用esi做指针的时候得用这句取消定义
这样寄存器可以用逗点引用字段名
结构体的定义可以嵌套:
NEW_WNDCLASS struct
dwOption dword ?
oldWndClass WNDCLASS <>
…
NEW_WNDCLASS ends
假设现在esi是指向一个NEW_WNDCLASS的指针,那么引用嵌套的oldWndClass中的lpfnWndProc字段时,
就可以用下面的语句:
mov eax, [esi].oldWndClass.lpfnWndProc
指定长度访问变量:
类型 ptr 变量名
例:
mov eax, dword ptr szBuffer
变量的尺寸:
sizeof 变量名,数据类型,结构体 ;可以取得以字节为单位的长度
lengthof 变量名,数据类型,结构体 ;可以取得变量中数据的项数
获取变量的地址:
对于全局变量,地址在编译的时候已经由编译器确定,所以用:
mov 寄存器, offset 变量名 ;offset伪指令操作是在编译时完成的
取得局部变量的地址:
addr 局部变量名或全局变量名
后跟全局变量名时,编译器自动按照offset的用法使用,
后面跟局部变量名的时候,编译器会自动用lea指令先把地址取到eax中,然后用eax来代替变量地址.
addr伪指令对局部变量取地址时,只能用在invoke的参数中,不能用在mov指令中.
它的左边不能用eax,不然会被覆盖掉.