程序开发
- 伪指令
- 全局变量定义
- 类型:
- 无符号字节:
BYTE、DB。 - 无符号字:
WORD、DW。 - 无符号双字:
DWORD、DD。 - 无符号远字(3 字节):
FWORD、DF。 - 无符号四字:
QWORD、DQ。 - 无符号十字节:
TBYTE、DT。 - 有符号字节:
SBYTE。 - 有符号字:
SWORD。 - 有符号双字:
SDWORD。 - 单精度浮点数:
REAL4。 - 双精度浮点数:
REAL8。 - 扩展精度浮点数:
REAL10。
- 无符号字节:
- 定义格式:
[<VAR-NAME>] <TYPE> <VAR-VALUE>。- 变量名实际上只是标签,加上变量名后,把这个位置的地址绑定到变量。
<VAR-VALUE>可以是数组,元素用,分隔。- 用
<CNT> DUP(<ELEM1>, <ELEM2>, ...)可以重复n次<ELEM1>, <ELEM2>, ...。DUP可以嵌套。 - 用
?表示不初始化。
- 类型:
EQU- 用表达式定义常量符号,语法
<SYM> EQU <EXPR>。 - 使用
EQU定义后的符号不能重定义。
- 用表达式定义常量符号,语法
=- 与
EQU类似,但是表达式只能是数值表达式,符号可以重定义。
- 与
$- 表示使用
$处的地址计数器值。 - 在定义变量或编写指令时,都会移动地址。
- 常用
$确定数组的占用空间,如arr WORD 0102h, 1000, 100*100 bytes EQU $-arr
- 表示使用
- 取地址
OFFSET <VAR>:取变量<VAR>的偏移地址,类似 C 语言的&<VAR>。SEG <VAR>:取变量<VAR>所在段基址。
- 算术、逻辑、关系运算
- 如果表达式是常量表达式,则可以在指令中直接使用。
- 算术:
+、-、*、/、MOD。 - 逻辑:
AND、OR、XOR、NOT。 - 算术:
EQ、NE、LT、GT、LE、GE。
- 框架定义
- 指令集定义:
- 指定使用的指令集,默认是 8086 指令集。
- 使用
.386指定 i386 指令集,.386p指定特权模式下运行的变种。
- 工作模式定义:
- 一般用
.MODEL FLAT, STDCALL,表示平坦内存模式、stdcall 调用约定。
- 一般用
- 段定义:
.DATA:数据段。.DATA?:未初始化的数据段。.CONST:常量。.CODE:代码段。特权级 3 的程序的代码段一定只读。
- 指令集定义:
ENDEND [<ENTRY-POINT>]。- 遇到此伪指令后,汇编器停止处理文件。
<ENTRY-POINT>是可选的,只需要在要指定程序入口时使用。
EXTERN- 在变量前加上,则表示此变量来源于其他单元。
PUBLIC- 在变量前加上,则表示其他单元可以引用此变量。
- 函数声明
<FUNC-NAME> PROTO [<CALLING-CONVENTION>] :<ARG1-TYPE>, :<ARG2-TYPE>, ...。- 不需要声明返回类型,返回值通过
AX传递。 - 如果含有可变参数,使用
:VARARG。 - 调用约定省略时,使用
.MODEL中规定的调用约定。
- 函数调用
INVOKE <FUNC-NAME> <ARG1>, <ARG2>, ...。- 自动生成传参、调用后清理的代码,根据调用约定自动生成不同的代码。
- 传递的参数必须可以直接作为
PUSH的操作数,不能有额外的计算。
- 函数/过程定义
<FUNC-NAME> PROC [<CALLING-CONVENTION>] <ARG1>:<ARG1-TYPE>, <ARG2>:<ARG2-TYPE>, ... <CODES> RET <FUNC-NAME> ENDP- 使用伪指令定义后,自动生成符合调用约定的函数开始、结束代码。
- 代码中可以直接使用参数名引用参数。
RET不需要额外操作数,操作数根据调用约定和参数个数自动生成。BP的值不能随意改变,伪指令需要使用BP作为基址引用参数、局部变量。
- 局部变量定义
LOCAL <VAR1>[[<SIZE>]]:<VAR1-TYPE>, ...- 变量可以定义为数组,访问时也使用
[]引用特定元素。
- 全局变量定义
- i386 Windows MSVC 调用约定
- cdecl
- 参数从右向左压入栈。
- 调用者负责在调用后清理栈,支持可变参数函数。
- 返回值通过
EAX返回。 EAX、ECX、EDX为调用者保存,EBX、ESI、EDI、EBP为被调用者保存。- 栈以 4 字节对齐。
- stdcall
- 被调用者负责在返回时清理栈,因此不支持可变参数函数。
- 其他与 cdecl 相同。
- fastcall
- 前两个 32 位整型或指针参数通过
ECX和EDX依次传递,其他参数从右向左压入栈。 - 其他与 stdcall 相同。
- 前两个 32 位整型或指针参数通过
- naked
- 伪指令不生成函数序言或尾声,既不保存寄存器也不调整栈指针。
- cdecl