Windows编程学习记录(七)—— 基本语法

1.标号&变量&数据结构

1.1 标号

格式1: 标号:    目的指令

格式2: 标号::目的指令

在WIN32编程使用的高版本MASM中,格式1的标号只在同一个子程序中唯一,所以不能用格式1的标号跳转到其他子程序。格式2的标号整个程序唯一,所以可以跳到其他子程序。但这种跳转就像在c语言中写goto一样,最好少用。

@@:,@B, @F是常用的简便方法,避免每一个小跳转都要起名。JMP @B会跳转到前一个@@,JMP @F会调转到后一个@@处。使用@@不应该距离太远,避免程序维护时在中间加入了新的@@导致出错。

1.2 全局变量

全局变量定义在.data段 或.data?段,变量类型如下表

名称

表示方式

缩写

长度(字节)

字节

byte

db

1

word

dw

2

双字(double word)

dword

dd

4

三字(far word)

fword

df

6

四字(quad word)

qword

dq

8

十字节BCD码(ten byte)

tbyte

dt

10

有符号字节(sign byte)

sbyte

 

1

有符号字(sign word)

sword

 

2

有符号双字(sign dword)

sdword

 

4

单精度浮点数

real4

 

4

双精度浮点数

real8

 

8

10字节浮点数

real10

 

10

只有在定义全局变量的时候可以用缩写。

.data?段定义的变量不能在定义的时候指定初值,这个初值是固定的0,所以如果初值本来就要设置为0的话可以省略初始化的步骤。这和局部变量就不同了,局部变量一定要清零处理,否则可能出现不确定的异常。

1.3 局部变量

局部变量是存储在子程序的堆栈中的。进入程序时,修改栈顶指针esp留出存储局部变量所需要的空间,然后将局部变量入栈。子程序返回时,恢复esp,这段用于存储局部变量的栈就被弃用,这样就可以实现变量的无效化处理。

MASM提供了一个伪指令用于定义局部变量:

local       变量名1[[重复数量]][:类型],变量名2[重复数量][:类型]……

如:

local loc1[1024] :byte, loc 2:WNDCLASS 

含有局部变量的子程序调试时可以看到这样的特征:

push ebp
mov  ebp,esp
sub  esp,xxxx
……
leave 

这里的leave就等于mov esp,ebp和pop ebp,等于恢复了子程序执行前ebp和esp的状态。 

 

2.数据结构&变量使用&子程序

 

2.1 数据结构 

类似于C语言中的结构体,是自定义的数据类型,作为一种数据的模板。定义的格式如下:

结构名 struct

字段1  类型  ?
字段2  类型  ?
……

结构名 ends

在数据段中使用数据结构定义的方法:

        .data?
变量名    结构名    <>


        .data
变量名    结构名    <初值1,初值2,……>

要使用结构体成员有三种方法:

(1)变量名.成员名

(2)[指针+结构名.成员名]        相当于基地址加偏移

(3)mov esi, offset 变量名

    assume esi:ptr 结构名

    [esi].成员名

不用的时候assume esi:nothing

 

2.2 变量使用

2.2.1 以不同的类型访问变量

类似于C语言中的强制类型转换。但在WIN32汇编中不会改变数据类型,只是在执行指令时不检测数据的长度。使用的方法:

类型 ptr 变量名

如:

mov ax,word ptr szBuffer

这样就会把szBuffer起始地址开始的两个字节存入ax中

应当注意的是这种方式访问数据不会检测长度是否溢出了,所以有可能会读到别的变量的数据,如果只是想进行字节的扩展,可以使用movzx,movsx指令。

2.2.2 变量的尺寸和数量

sizeof 伪指令可以取得变量、数据类型或数据结构以字节为单位的长度,lengthof 可以取得变量中数据的项数。

应该注意的是设计字符串的长度最好用lstrlen计算,因为MASM中变量定义只识别一行,如:

szHello              db               'Hello', 0ah, 0ah
                                 db               'World' ,0

MASM只会识别第一行为szHello,第二行识别为没有命名的另一个变量,所以对szHello使用sizeof就只能得到第一行的长度

2.2.3  获取变量地址

对于全局变量,可以使用 mov 寄存器,offset 全局变量名,因为全局变量的地址是固定的,所以在编译时编译器就直接将offset 全局变量名替换为地址写入程序。但对于局部变量,只有在程序加载进内存后才能确定地址,所以不能用offset获取地址。一般使用ebp做指针进行访问,用lea指令传地址。

MASM提供了一个伪指令addr 局部变量名,编译器将局部变量的地址用lea传入eax寄存器中,在用eax代替变量地址使用,

addr伪指令只能使用在invoke语句中,如mov eax,addr 变量名这样的用法是错误的。

与此同时,因为使用了eax寄存器,所以在用了addr的invoke语句中就最好不要再使用eax传参了,否则会出现数据的覆盖。
 

2.3 子程序 

2.3.1 子程序的定义

2.3.2 参数传递和堆栈平衡

这两个部分前面都记录过了,这里就省略了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值