程序开发

  • 伪指令
    • 全局变量定义
      • 类型:
        • 无符号字节:BYTEDB
        • 无符号字:WORDDW
        • 无符号双字:DWORDDD
        • 无符号远字(3 字节):FWORDDF
        • 无符号四字:QWORDDQ
        • 无符号十字节:TBYTEDT
        • 有符号字节: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
      • 逻辑:ANDORXORNOT
      • 算术:EQNELTGTLEGE
    • 框架定义
      • 指令集定义:
        • 指定使用的指令集,默认是 8086 指令集。
        • 使用 .386 指定 i386 指令集,.386p 指定特权模式下运行的变种。
      • 工作模式定义:
        • 一般用 .MODEL FLAT, STDCALL,表示平坦内存模式、stdcall 调用约定。
      • 段定义:
        • .DATA:数据段。
        • .DATA?:未初始化的数据段。
        • .CONST:常量。
        • .CODE:代码段。特权级 3 的程序的代码段一定只读。
    • END
      • END [<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 返回。
      • EAXECXEDX 为调用者保存,EBXESIEDIEBP 为被调用者保存。
      • 栈以 4 字节对齐。
    • stdcall
      • 被调用者负责在返回时清理栈,因此不支持可变参数函数。
      • 其他与 cdecl 相同。
    • fastcall
      • 前两个 32 位整型或指针参数通过 ECXEDX 依次传递,其他参数从右向左压入栈。
      • 其他与 stdcall 相同。
    • naked
      • 伪指令不生成函数序言或尾声,既不保存寄存器也不调整栈指针。