模式定义
.386
.model flat,stdcall
option casemap:none
- .386语句是汇编语言的伪指令,用于告诉编译器在本程序中使用的指令集。
-
.model语句用来定义程序工作的模式,它的用法是:
.mode 内存模式 [,语言模式] [,其他模式]
内存模式
模式 | 内存使用方式 |
---|---|
tiny | 用来建立 .com文件,所有的代码、数据和堆栈都在同一个64KB段内 |
small | 建立代码和数据分别用一个64KB段的 .exe文件 |
medium | 代码段可以有多个64KB段,数据段只有一个64KB段 |
compact | 代码段只有一个64KB段,数据段可以有多个64KB段 |
large | 代码段和数据段都可以有多个64KB段 |
huge | 同large,并且数据段中的一个数组也可以超过64KB |
flat | Win32程序使用的模式,代码和数据段使用同一个4GB段 |
- option语句定义的选项有很多,在win32汇编程序中,需要的只是定义option casemap:none,这个语句定义了程序中的变量和子程序名是否对大小写敏感,由于Win32 API名称是区分大小写的,所以必须指定这个选项,否则在调用API的时候会有问题
段的定义
数据段
-
.data,.data?和.const定义的是数据段,分别对应不同方式的数据定义,在最后生成的可执行文件中也分别放在不同的节区(Section)中。程序中的数据定义一般可以归纳为3类
- 可读可写的已定义变量。这些数据在源程序中已经被定义了初始值,而且在程序的执行中有可能被更改,如一些标志等,这些数据必须定义在.data段中,.data段一般存放在可执行文件的_DATA节区内。
-
可读可写的未定义变量。这些变量一般是当做缓冲区或者在程序执行后才开始使用的。这些数据可以定义在.data段中,也可以定义在.data?段中,但一般把它放到.data?段中。虽然定义在这两种段中都可以正常使用,但定义在.data?段中不会增大.exe文件的大小。
3.可读不可写的常量。如一些要显示的字符串信息,他们在程序装入的时候已经有效,在整个执行过程中不需要修改,这些数据可以放在 .const段中, .const段是常量段,它是可读不可写的
代码段
- .code段是代码段,所有的指令都必须写在代码段中,在可执行文件中,代码段一般是放在_TEXT节区中的,Win32环境中的数据段是不可执行的,只有代码段的属性。对于工作在特权级3的应用程序来说,.code段是不可写的。
堆栈段
- 在程序中不必定义堆栈段,系统会自动分配堆栈空间。堆栈段的内存属性是可读可写可执行的。
调用API
使用invoke语句
invoke 函数名 [,参数1] [,参数2]......
函数的声明
在调用API函数的时候,函数原型也必须预先声明,否则,编译器会不认这个函数。invoke伪指令也无法检查参数个数。声明函数的格式是:
函数名 proto [距离] [语言] [参数1]:数据类型, [参数2]:数据类型,......
- proto是函数声明的伪指令
- 距离 可以是NEAR,FAR,NEAR16,NEAR32,FAR16或FAR32,Win32只有一个平坦的段,无所谓距离,所以在定义时是忽略的
- 语言类型就是 .model那些类型,如果忽略,则使用.model定义的默认值
- 参数,由于Win32 API仅仅使用了dword类型的参数,所以绝大多数的数据类型都是doword。
include语句
- 在Win32汇编中使用API函数,程序必须知道调用的API函数存在于哪个DLL中,否则操作系统必须搜索系统中存在的所有DLL,并且无法处理不同DLL中的同名函数,所以必须有个文件包括DLL库正确的定位信息,这个任务是由导入库来实现的。
includelib 库文件名
或
includelib <库文件名>
全局变量
全局变量的定义
Win32汇编的全局变量定义在.data或.data?段内,可以同时定义变量的类型和长度:
变量名 类型 初始值1,初始值2,......
变量名 类型 重复数量 dup (初始值1,初始值2,......)
变量的类型
名称 | 表示方式 | 缩写 | 长度(字节) |
---|---|---|---|
字节 | byte | db | 1 |
字 | word | dw | 2 |
双字 | dword | dd | 4 |
三字 | fword | df | 6 |
四字 | qword | dq | 8 |
十字节BCD码 | tbyte | dt | 10 |
有符号字节 | sbyte | 1 | |
有符号字 | sword | 2 | |
有符号双字 | sdword | 4 | |
单精度浮点数 | real4 | 4 | |
双精度浮点数 | real8 | 8 | |
10字节浮点数 | real10 | 10 |
局部变量的定义
local 变量1[[重复数量]] [:类型],变量2[[重复数量]] [:类型]......
- local伪指令必须紧接在子程序定义的伪指令proc后,数据类型不能缩写,默认的类型是dword。局部变量的作用域是当前的子程序。
子程序的定义
子程序名 proc [距离] [语言类型] [可视区域] [USES 寄存器列表] [,参数:类型] ......[VARARG]
local 局部变量列表
程序
子程序名 endp
- 距离——可以是NEAR,FAR等,win32中只有一个平坦的段,所以对距离的定义忽略
- 语言类型——表示参数的使用方式和堆栈平衡的方式,如果忽略,则使用程序头部.mode定义的值
- 可视区域——可以是PRIVATE,PUBLIC和EXPORT。PRIVATE表示子程序只对本模块可见;PUBLIC表示对所有的模块可见(在最后编译链接完成的.exe文件中);EXPORT表示是导出函数,当编写DLL的时候要将某个函数导出的时候可以这样使用。默认的设置是PUBLIC。
- USES寄存器列表——表示由编译器在子程序指令开始前自动安排push这些寄存器指令,并且在ret前自动安排pop指令,用于保存执行环境。
- 参数——参数指参数的名称,在定义参数名的时候不能跟全局变量和子程序中的局部变量重名。
- 类型——由于win32中的参数类型只有32位(dword)一种类型,所以可以忽略。
- VARARG——表示在已确定的参数后还可以跟多个数量不确定的参数,在Win32汇编中唯一使用VARARG的API就是wsprintf。
不同语言调用方式的差别
C | SysCall | StdCall | BASIC | FORTRAN | PASCAL | |
---|---|---|---|---|---|---|
最先入栈参数 | 右 | 右 | 右 | 左 | 左 | 左 |
清除堆栈者 | 调用者 | 子程序 | 子程序 | 子程序 | 子程序 | 子程序 |
最先入栈参数 | 是 | 是 | 是 | 否 | 否 | 否 |
分支语句
.if 条件表达式1
表达式1为“真”时执行的指令
[.elseif 条件表达式2]
表达式2为“真”时执行的指令
[.elseif 条件表达式3]
表达式3为“真”时执行的指令
.....
[.else]
所有表达式为“否”时执行的指令
.endif
循环语句
.while 条件测试表达式
指令
[.break [.if 退出条件]]
[.continue]
.endw
或
.repeat
指令
[.break [.if 退出条件]]
[.continue]
.until 条件测试表达式 (或.untilcxz [条件测试表达式1])
使用标号@@
- 当@@做标号时,可以用@F和@B来引用它,@F表示本指令后的第一个@@标号,@B表示本指令前的第一个@@标号,程序中可以有多个@@标号,但是@B和@F只寻找匹配最近的一个。
版权声明:本文为qq_17111397原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。