读书人

学 Win32 汇编[34] - 宏汇编(一)

发布时间: 2012-09-20 09:36:50 作者: rapoo

学 Win32 汇编[34] - 宏汇编(1)

从接触 C 语言时, 我就不大喜欢宏; 但为了看懂别人的代码也不得不去了解.

宏可定义在源程序的任意位置, 但一般放在 .data 前面.
有些简单的宏可以用 equ、textequ 或 = 来代替, 但宏有更复杂的功能.

"宏" 的本质是 "替换", 但又像极了 "子过程";
所以即有宏过程(macro procedure)、也有宏函数(macro function).
它既以有参数(可以是: 常数、变量、寄存器、指令、表达式), 有时也需要像子过程一样声明.
宏可以指定哪些参数是必须的, 还可以给参数默认值.

宏可以包含数据(.data)和代码(.code)、还可以嵌套.
宏中的注释使用 ;; 如果只用 ; 将会被一起替换到代码中.

宏的功能很强大, 现在常用的 PrintDec、PrintHex、PrintString、PrintText 等等都是宏.
再强大它也只是 "文本替换".

"宏" 和 "子程序" 相比:
1、宏展开后顺序执行, 不像调用子程序跳来跳去, 这样程序会更 "快";
2、宏展开后会让代码量增大, 导致程序变 "大".


一个简单的宏:

; Test34_1.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.lib;定义一个 mExit 宏mExit macro?   PrintLine?   retendm.codesum proc v1, v2, v3?   mov eax, v1?   add eax, v2?   add eax, v3?   retsum endp;main proc?   invoke sum, 11, 22, 33?   PrintDec eax ;66    ;PrintLine    ;ret?   mExit ;mExit 将被替换为上面两行代码main endpend main


一个代替求和函数的宏:

; Test34_2.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.libmSum macro v1, v2, v3?   mov eax, v1?   add eax, v2?   add eax, v3endm.codemain proc?   mSum 11, 22, 33?   PrintDec eax ;66?   PrintLine?   mSum 11, 22, 33, 44, 55 ;多余的参数会被忽略?   PrintDec eax ;66?   PrintLine?   retmain endpend main


宏参数的默认值:

; Test34_3.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.lib;参数 v1、v2 通过 REQ 标识说明是必备参数;参数 v3、v4 给出了默认值mSum macro v1:req, v2:req, v3:=<33>, v4:=<44>?   mov eax, v1?   add eax, v2?   add eax, v3?   add eax, v4endm.codemain proc?   mSum 11, 22?   PrintDec eax ;110?   PrintLine?   retmain endpend main


EXITM: 退出宏

; Test34_4.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.libmPrint macro?   PrintText '第一行'?   PrintText '第二行'?   exitm?   PrintText '第三行'endm.codemain proc?   mPrint ;只会输出前两行?   retmain endpend main


PURGE: 取消宏

; Test34_5.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.libmPrint macro?   PrintText '第一行'?   PrintText '第二行'?   PrintText '第三行'?   PrintLineendm.codemain proc?   mPrint?   mPrint?   purge mPrint ;可用逗号隔开取消多个宏?   mPrint?      ;这个宏不会展开了?   retmain endpend main


宏中 local 的使用:

; Test34_6.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.lib;从三个数中求最大数的宏mMax macro v1, v2, v3?   LOCAL L1, L2 ;;如没有这句, 宏在多次展开时会让 L1、L2 重名, 这样宏会把标号名称协调好?   mov eax, v1?   cmp eax, v2?   jge L1?   mov eax, v2L1: cmp eax, v3?   jge L2?   mov eax, v3L2:endm.codemain proc?   mMax 11, 22, 33?   PrintDec eax  ;33?   retmain endpend main


灵活的参数, 用到 & 操作符:

; Test34_7.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.lib;求最数中的最大值:mMax macro v1, v2?   LOCAL L1?   mov eax, v1?   cmp eax, v2?   jge L1?   mov eax, v2L1:endm;求最数中的最小值:mMin macro v1, v2?   LOCAL L1?   mov eax, v1?   cmp eax, v2?   jle L1?   mov eax, v2L1:endm;能把 JGE 或 JLE 做参数:mCom1 macro XX, v1, v2?   LOCAL L1?   mov eax, v1?   cmp eax, v2?   XX L1?   mov eax, v2L1:endm;能通过参数让 J*E 变为 JGE 或 JLE:mCom2 macro X, v1, v2?   LOCAL L1?   mov eax, v1?   cmp eax, v2?   J&X&E L1    ;;这里用到特殊操作符 &?   mov eax, v2L1:endm.codemain proc?   mMax 11, 22?   PrintDec eax ;22?   ?   mMin 11, 22?   PrintDec eax ;11?   ?   mCom1 JGE, 11, 22?   PrintDec eax ;22?   ?   mCom1 JLE, 11, 22?   PrintDec eax ;11?   ?   mCom2 G, 11, 22?   PrintDec eax ;22?   ?   mCom2 L, 11, 22?   PrintDec eax ;11?   retmain endpend main


特殊操作符: &、<>、%、!

&  ;替换操作符<> ;字符串传递操作符%  ;表达式操作符, 也用于得到一个变量或常量的值!  ;转义操作符; Test34_8.asm.386.model flat, stdcallinclude    windows.incinclude    kernel32.incinclude    masm32.incinclude    debug.incincludelib kernel32.libincludelib masm32.libincludelib debug.lib;自定义的宏mPrint macro Text?   PrintText '* &Text& *'endm.codemain proc    ;该宏会把参数直接替换过去?   mPrint 1234    ;* 1234 *?       ;要保证参数的完整应该使用 <>?   mPrint 12,34   ;* 12 *?   mPrint <12,34> ;* 12,34 *?       ;需要计算结果应该使用 %()?   mPrint 34+12   ;* 34+12 *?   mPrint %(34+12)   ;* 46 *?       ;用到 &、<、>、%、! 应该使用 ! 转义?   mPrint 10 !% 2 = %(10/2)!! ;* 10 % 2 = 5! *?   retmain endpend main

读书人网 >编程

热点推荐