Win32汇编_变量

全局变量:
全局变量的作用域是整个程序,Win32汇编的全局变量定义在.data.data?段内,可以同时定义变量的类型和长度.
格式是:
变量名     类型   初始值1, 初始值2, …
变量名     类型   重复数量  dup  (初始值1, 初始值2, …)

clip_image002

:
.data         ;
全局变量的类型才可以用缩写
wHour          dw       ?                     ;
未初始化的word类型变量
wMinute       dw       10                    ;
初始化为10word类型变量
_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,不然会被覆盖掉.

posted on 2010-08-20 12:49  o无尘o  阅读(2051)  评论(0编辑  收藏  举报