当前位置:文档之家› 汇编语言——宏

汇编语言——宏


【例7.14】形式参数还可以出现在变量定义伪操作的初值表 中,甚至是以字符串形式出现的初值。
msg MACRO num,pname
var&num DB
ENDM
'HELLO, &pname'
汇编语言规定,字符串中的形参必须用分隔符“&”从其它 部分分离出来。对于下面两个宏调用, msg msg 1,John 2,Henrry
在前面标以加号“+”以示区别。
【例7.10】参照汇编程序的处理方法,对下面程序中的宏进
行展开。 back = 4CH 21H
dosint EQU dispch MACRO MOV MOV INT ENDM
AH,2 DL, '* ' 21H
code
SEGMENT ASSUME CS:code
main:
是有限制的,所以源程序中在不同位置调用这样的宏,那些
离标号定义处较近的可以不超过范围因而没有语法错误,但 那些离标号定义处远的就不保证了。
【格式】LOCAL 标号1, 标号2, … 【功能】用于告诉汇编程序,在宏展开时,对宏体中出
现的“标号1”、“标号2”等标号定义,代换为特殊的各不相
同的标号。汇编程序在遇到用LOCAL说明的标号时,会代 以??0000、??0001、?0002、……等特殊的标识符,以保证宏
体中的标号定义在每次宏展开时各不相同,避免重复定义的
情况。
【例7.16】设有如下宏定义:
sum MACRO a,b LOCAL next
MOV CX,a
LEA BX,b XOR AX,AX
next:ADD AX,[BX]
ADD BX,2 LOOP next
ENDM
并已知 buf1 和 buf2 是已定义的两个变量,展开下面的宏调用: sum 5,buf1 sum 7,buf2
MOV AX,x
MUL AX
ENDM
mm2 MACRO a,b,c mm1 a
MOV BX,AX
mm1 b
ADD AX,BX MOV c,AX ENDM

mm2 v1,v2,v3
【解】展开mm2后得到: + mm1 v1 + MOV BX,AX + mm1 v2 + ADD AX,BX + MOV v3,AX 其中还含有宏调用,再把两个mm1展开后可得到如下结果: + MOV AX,v1 + MUL AX + MOV BX,AX + MOV AX,v2 + MUL AX + ADD AX,BX + MOV v3,AX
(3)宏定义仅仅用来告诉汇编程序,将来宏调用时复制
的对象是什么,宏定义中的程序段并不是程序的一部分,也 就是说,如果程序中定义了一个宏而没有调用它,汇编程序 将忽略宏定义。 (4)宏定义可以写在程序的任何地方,但习惯上总是把
宏定义写在程序的最前面。
宏定义与编辑器中的文字块的定义有相似之处,也有一 些差别。两者都需要以特定的方式说明开始和结束的位置。 文字块是文件的一部分,而宏体中的程序段必须经过宏调用 才能复制到源程序中正确的位置,没有被调用的宏体在汇编 程序翻译时会被忽略。
编程序会把这样的标识符当作宏进行处理,而使得源程序中
无法使用其原有的功能。汇编语言中还提供了一个PURGE伪 指令,用于在源程序适当的位置取消某个宏。比如:
add MACRO x,y
ENDM ADD AX,BX

PURGE add ADD AX,BX
这样的源程序中,前一个ADD被当作宏调用处理(汇编 语言是不分大小写的),进行宏展开;后一个ADD由于已用 PURGE伪指令取消了作为宏的add宏调用,使得该标识符恢 复原功能,因此是ADD指令。
可以看到,两次调用宏 sum ,展开后的结果中标号分别 是??0000和??0001,是不同的。如果宏定义中没有LOCAL伪 操作,展开结果中将在两个地方定义标号 next,是重复定义。 汇编语言还规定,LOCAL伪操作必须出现在宏体的第1 行上,在“宏名 MACRO”与LOCAL伪操作之间不允许有任
现为指令助记符)含有形式参数,符号“&”用于把形参cmd 从标识符中分离出来。如果没有分隔符号“&”,汇编程序将 把Jcmd作为一个整体处理,而不知道其中的cmd是形参。 对例7.12后面的3个调用,调用例7.13中的宏可以达到同
样的效果,相应写法是:
cc1 cc1 cc1 G,n1 BE,n2 NZ,n3
宏展开的结果是: + var1 DB 'HELLO, John'
+ var2
DB
'HELLO, Henrry'
*7.3.4 宏操作中形参与实参的对应关系
由于宏是伪操作,形参与实参的对应方法是由汇编程序 决定的,与高级语言中形参与实参的对应方式有很大的不同。
汇编语言规定:
(1)形参表中的多个参数项之间必须用逗号分隔,但实 参表的各个参数项可以用逗号也可以用空格分隔。 (2)如果形参的数目与实参的数目相等,则按照形参表 与实参表中各参数项的次序一一对应。
(3)如果形参数目少于实参数目,多余的实参被忽略,
汇编程序不做任何提示。
(4)如果形参数目多于实参数目,不足的实参作空串处 理,汇编程序也不做提示。 (5)如果实参中包含逗号、空格等分隔符作有效符号, 必须用尖括号“< >”括起来,避免混淆。
【例7.15】设有宏定义如下:
data MACRO p,q v&p DB q
由于宏展开是汇编程序翻译的一个步骤,宏展后的结果
并不是源程序,所以展开后不再写出完整的程序格式,只列 出有效指令部分。
可以看到,汇编程序对宏调用与已定义的常量及符号的
引用的处理是很类似的,定义部分在汇编处理结束后就已完 成它的作用。汇编程序翻译后得到的机器代码中没有宏、常 量等的定义,只是调用或引用部分被代换成宏体或定义的内 容。宏与常量定义及符号定义的差别在于,常量及符号定义
cc
JG,n1
JBE,n2
cc
JNZ,n3
【例7.13】宏的形式参数可以作为一个标识符的一部分。这 时,必须用符号“&”把形式参数与标识符的其余部分分开。 例7.12中的宏定义还可以写成下面的形式: cc1 MACRO CMP J&cmd ENDM cmd,lab AX,BX lab
宏体中第2行的J&cmd就是在一个标识符中(例7.13中表
ENDM
以及下面的宏调用: x x data + v1 = = %x,%x DB 1 1 x+1 data %x,%x
其宏展开结果是:
+ v2
DB
2
பைடு நூலகம்
符号“%”的作用体现在宏展开中是用常量标识符x的值
(第1次宏调用时是1,第2次宏调用时是2),而不是符号x本 身,去替换宏展开时的形参。 需要注意的是,宏操作与源程序的其它部分一样,都要 经过汇编程序的处理。汇编程序在处理带有宏调用的程序时,
7.3.5 宏体中的标号
宏体中出现标号分为两种情况:一是在带有跳转功能的
指令中,标号作为跳转的目的地,也就是对标号的引用;另
一种是宏体中某条指令的前面出现标号,即标号定义。如果 宏体中引用标号,由于汇编语言允许从程序的不同地方用跳
转指令跳转到同一位置,所以即使源程序中对这样的宏多次
调用,展开后的结果并不违反语法规则。但是需要注意,如 果标号的引用出现在条件跳转指令中,由于条件跳转的距离
【例7.11】普通用法,形式参数出现在操作数的位置。
dch MACRO MOV AH,2 x
MOV
INT ENDM
DL,x
21H
源程序中调用宏dch时,应该在宏名字的后面跟一个实际 参数,从例7.11的宏体可以看出,这个实际参数应该是用于屏 幕显示的一个ASCII字符。因而,源程序中用下面的写法连续 两次调用上述宏,就可以实现回车换行操作。宏展开时,对每 一次宏调用,将分别以相应的实际参数代换宏体中的形式参数。
因此,对这一类错误提示,程序员只能自己按规则进行宏展 开,并判断展开后的结果是如何出的错。对于MASM汇编程 序比较熟悉的人,还可以借助于MASM处理源程序时产生的 一个.LST文件(只要在MASM提问“Source listing[NUL.LST]” 时输入一个合适的文件名即可产生清单文件),判断程序中 的错误,以及查看宏展开的结果。 另外,宏调用的优先级高于其它伪指令和指令,所以如 果用伪指令或指令助记符等内部保留字作为宏的名字,则汇
是先进行宏展开,再进行语法检查及翻译。宏体在定义时,
由于可以带有一些形式参数,在没有进行代换之前很可能是 不符合语法规则的,但宏调用并展开后是否符合语法规则,
需要由汇编程序来判定。如果展开后的指令或伪指令有错,
汇编程序只能指出宏调用有错,并指出宏调用所在行的号码, 却无法指出究竟是展开后的哪一行不符合语法。
7.3.7 宏与子程序的比较
(1)处理的时间不同。宏调用是在源程序被汇编时由汇
编程序处理的;而子程序调用是在程序执行期间由 CPU直接
执行的。 (2)处理的方式不同。宏必须先定义后调用,宏调用是 用宏体替换宏调用伪指令,实参代替形参,源程序被翻译成 目标代码后宏定义随之消失;而子程序的调用没有这样的替 换操作,是以CALL指令将控制权由调用者转给子程序
7.3.2 宏调用 定义后的宏名又称为宏指令。经宏定义后,就可以在 源程序中调用宏了。宏调用的方式是在源程序中需要复制
宏体的地方写宏的名字。宏名单独占一行,当源程序被汇
编时,汇编程序将对宏调用进行宏体复制,并取代宏名, 这种复制操作称为宏展开。为了与源程序的其它部分相区
别,后面的叙述中,对由宏调用而展开后得到的指令,都
7.3 宏
程序中使用宏分为定义和调用两个部分。宏定义用来说
明哪些指令或伪指令是将在程序中重复出现的程序段;宏调
相关主题