灵活的运用带参数的宏可以十分方便地编写程序,这是因为宏的参数不仅可以是指令的操作数,而且还可以是具体的指令,甚至于是某个指令的一部分。比如下面这个例子就是采用指令作为宏的参数:
ope MACRO pa1,pa2,pa3,pa4 mov ax,pa1 pa2 pa3 pa4 ENDM
如果我们这样调用宏OPE:
OPE 200H,DEC,AX,CWD
那么编译之后这个宏将被展开为:
mov ax,200h
dec ax
cwd
参数中的200H与AX是指令操作数,而DEC与CWD却是实实在在的指令。如果我们换用其它指令,比如说这样调用OPE:
OPE CX,PUSH,AX,CLC
这时编译程序就会把OPE宏展开为:
mov ax,cx
push ax
clc
可见这个宏可以称为千变万化了。
宏OPE的变化还是很普通的,下面这个例子所显示出的变化就更吸引人了:
compare MACRO pa1,pa2,pa3,pa4
cmp pa1,pa2
j&pa3 pa4
ENDM
如果这样来调用宏COMPARE:
COMPARE AX,200H,NZ,EXIT
则编译之后这个宏会被展开为:
cmp ax,200h
jnz exit
参数中的"NZ"其实是作为指令"JNZ"的一部分给出的。另一部分"J"在宏的内部。这里要注意字符"&"不可以丢掉。与OPE宏一样,如果把参数做些变化,则这个宏就会被展开其它样子。比如:
COMPARE AX,BX,LE,NEXT
展开之后就是:
cmp ax,bx
jle next
带参数的宏还有其它一些活用的例子,限于篇幅不再详细讨论了。下面给出了一个宏汇编程序实例,这个程序可以将一个字符串中的大小写字母互相转换,将此程序编译连接之后大家可以自己用DEBUG观察反汇编结果,以研究源程序中应用宏的技巧。
print MACRO p1 ;输出字符串的宏 mov dx,offset p1 mov ah,09 int 21h ENDM comp MACRO pa1,pa2,pa3 ;用于进行数据比较的宏 cmp al,pa1 ;将参数PA1与AL寄存器中的数据比较 j&pa2 next&pa3 ;根据PA2给出的条件及PA3给出的部分 ENDM ;目的地址进行转移 code segment assume cs:code,ds:code org 100h main proc near print msg ;输出转换前的字符串MSG mov si,offset msg ;SI、DI寄存器指向字符串 mov di,si next1: lodsb ;取得一个字符 comp 24h,z,3 ;将其与'$'进行比较,若相等转NEXT3 comp 20h,le,2 ;将其与空格相比较,若小于或等于空格符 ;转NEXT2 xor al,20h ;将大小写字母互换 next2: stosb ;将转换后的字符存回字符串 jmp next1 ;转NEXT1继续 next3: print msg ;输出转换后的字符串 ret ;结束进程 msg db 'Best Wish To YOU',0dh,0ah,24h main endp code ends end main
除了宏汇编技术之外,条件汇编也是一种高级的汇编技术。所谓条件汇编,指得是把源程序分成几个部分,编译时如果具备了某个条件则编译其中一个部分,如果相应条件不具备则编译其它部分。所以说,条件实际上是提供给编译程序处理的。
在具体讨论条件汇编技术之前我们先来看一看示例程序CHILD.ASM:
code segment assume cs:code org 100h main proc near mov ah,09 mov dx,offset msg int 21h int 20h msg db 'Hello ,cowboy!',0dh,0ah,07h,24h main endp code ends end main
这个程序的功能很简单,它只是在屏幕上显示一行文字--"Hello,cowboy!"。现在如果假设有一位很任性的小姑娘看到了这个程序显示的文字,她十分希望这个程序能显示出"Hello,cowgirl!",那么这个程序就要做些修改了。
说句老实话,修改程序比编写程序还要烦人,象这样的小程序当然看不出什么,对于一些比较大的程序来说修改工作可不比编写工作轻松。我们之所以强调要把程序中频繁使用的数据用"EQU"伪指令定义成常量,为的就是修改起来方便一些。