汇编语言——宏
宏汇编汇编语言

几个宏操作符的使用
%:表达式操作符:将其后面跟的表达式的值作为实参, 而不是将表达式本身作为参数,用在实参中。 &:替换操作符:用于将参数与其他字符分开。用在 宏体中。如果参数紧跟在其他字符之前或之后, 或者 参数出现在带引号的字符串中,就必须使用该伪操作 符。
宏汇编应用举例 例5-17 P148
multiply macro opr1,opr2,result
push dx push ax
; 定义宏
code segment assume
ds:data,cs:code,ss:stack start: mov ax,data
mov al,opr1 imul opr2 mov result,ax
在什么情况下使用宏?为什么要使用宏?
在汇编语言程序设计过程中,可以将具有一 定功能,需多次重复使用,且比较短的程序 段定义成一条宏指令。
使用宏指令语句可以减少程序书写错误,缩 短源程序长度,使源程序编写像高级语言一 样清晰、简洁。特别是使用宏库后,可以提 高编程效率。
比较
宏
子程序
➢ 仅是源程序级的简化: 宏调用在汇编时进行 程序语句的展开,不 需要返回;不减小目 标程序,执行速度没 有改变
5.6 宏结构程序设计
什么是宏?
宏是源程序中一段有独立功能的程序代码。 它只需在源程序中定义一次就可以多次调用它, 调用时,只需要用一个宏指令语句就可以了
宏(Macro)是汇编语言的一个特点,它是 与子程序类似又独具特色的另一种简化源程序的 方法
宏汇编
宏结构 重复汇编
8086汇编语言宏指令语句

Source listing[NUL.LST]: (源列表文件名)
列表文件名(缺省:无列 表文件)
Cross reference[NUL.CRF]: 交叉参考文件用的文件名 (缺省:无交叉参考文件) (交叉参考文件名)
第5章 汇编语言程序设计
5.2.3 用连接程序生成可执行程序文件(EXE 文件) 经汇编后产生的目标程序文件(OBJ文件)并不 是可执行程序文件,必须经连接后才能成为可执行文件 (EXE文件)。连接程序并不是专门为汇编语言程序设 计的,如果一个程序是由若干个模块组成的,也可以通 过连接程序把它们连接在一起。这些模块可以是汇编程 序产生的目标程序文件,也可以是高级语言编译程序产 生的目标程序文件。 完成连接功能的程序是LINK程序。连接过程如下 表所示:
第5章 汇编语言程序设计
⑵ 从程序的执行时间来分析,每调用一次子程序 都要保护和恢复返回地址(断点)及寄存器内容(现场) 等,要消耗较多的时间。宏指令调用时不需要这个过程, 执行时间较短。因此,从执行时间来分析,宏指令又优 于子程序。 综上所述,当某一需多次访问的程序段较长,访 问次数又不是太多时,选用子程序结构较好。当某一需 多次访问的程序段较短,访问次数又很频繁时,选用宏 指令结构显然要更好些。
库文件名表(各文件之间 用+号隔开)
第5章 汇编语言程序设计
DATA SEGMENT … DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA, ES:DATA START: MOV AX, DATA MOV DS, AX MOV ES, AX … MOV AH, 4CH INT 21H CODE ENDS END START
第5章 汇编语言程序设计
5.5.1 用编辑程序建立汇编语言源程序文件
汇编第7章 宏汇编

占用内存空间大
…
macro2
macroN
>EDIT EXP.ASM 调用宏库:
include MACRO.MAC …… macro1 [实元表] …… macro2 [实元表] …… macroN [实元表] ……
删除不用 的宏定义
purge macroN
汇编语言程序设计 汇编语言程序设计
子程序调用与宏调用工作方式的区别
宏定义: msg
errmsg
cntr=0 宏调用: …… errmsg …… errmsg 1 1 宏展开: 2 1 1 2 cntr msg msg1 …… cntr msg msg2
‘SYNTAX ERROR’
‘INVALID OPERAND’
= cntr+1 %cntr,‘SYNTAX ERROR’ db ‘SYNTAX ERROR’ = cntr+1 %cntr,‘INVALID OPERAND’ db ‘INVALID OPERAND’
指令:程序运行时执行的语句 汇编语言源程序 伪指令(伪操作):汇编时执行 宏指令:汇编时展开
汇编语言程序设计 汇编语言程序设计
一、 宏定义、宏调用和宏展开
宏定义: macro_name MACRO [哑元表] ; 形参/虚参 …… …… ; 宏定义体 ENDM
宏调用: (必须先定义后调用) macro_name [实元表] 宏展开: 宏定义体
汇编语言程序设计 汇编语言程序设计
三、宏汇编操作符: &
符号1 & 符号2
;;
%
宏展开时 , 合并前后两个符号形成一个符号。 & 可 以作为哑元的前缀。 ;; 注释 宏展开时,;; 后面的注释不予展开。 % 表达式
汇编语言——第3章宏汇编语言

第三章宏汇编语言一:宏汇编语言格式3.1.1 指令语句格式指令语句的一般格式如下:[标号:]指令助记符操作数;注释1.标号:标号是机械指令语句寄存地址的符号表示,代表该指令目标代码的第一个字节地址,后面必需紧跟冒号“:” 。
2.指令助记符:指令助记符为语句的核心成份,表示了该语句的操作类型。
3.操作数:操作数表示指令助记符的操作对象。
4.注释:注释均以分号开始,它可占一行或多行,一般放在一条语句的后面。
3.1.2 伪指令语句格式伪指令语句格式如下:[符号名] 伪指令符操作数;注释1.符号名:符号名是伪指令语句的一个可选项。
2.伪指令符:伪指令符指定汇编程序要完成的具体操作,如数据概念伪指令DB、DW、DD,段概念伪指令SEGMENT,假定伪指令ASSUME等。
2.操作数:伪指令后面的操作数能够是常数、字符串、变量、表达式等,其个数由具体的伪指令决定,各个操作数之间必需以“逗号”分隔。
4.注释:伪指令的注释必需以“;”开始,其作用同指令语句中的注释部份。
汇编语句表达式3.2.1 常量1.数值常量2. 字符串常量字符串常量是用单引号或双引号引发来的一个或多个字符。
字符串常量是以各字符的ASCⅡ码表示的。
如‘A’用41H 表示,字符串‘A1B2’用41H,31H,42H,32H表示。
3.2.2 变量1.变量(1)段属性(2)偏移地址属性(3)类型属性2.变量的概念表达式项是给变量或指定存储单元给予初值,它有以下几种形式:(1)数值表达式数据概念伪指令能够为一个或持续的存储单元设置数值初值。
【例】为数据段分派存储单元。
DATA SEGMENTA DB 11H,12H,13HB DW 1122H,3344HC DD HDATA ENDS上述变量的存储单元分派及初始化情形如下图所示。
数据段中数据存储分派图(2)字符串表达式字符串表达式中的字符串必需用引号引发来。
DB、DW、DD伪指令将字符串中的各字符均以ASCⅡ码形式寄存在相应的存储单元,但表示形式各不相同。
第4章 宏汇编语言

(4)分析运算符 分析运算符有SEG、 OFFSET、TYPE、LENGTH和 SIZE。分析运算符可以把一个存储单元的地址分解为 相应的段地址和偏移量。 ①SEG运算符
格式:SEG段名
功能:计算某个逻辑段的段基址。
②OFFSET运算符
格式:OFFSET变量名或标号名
功能:算出变量名(或标号名)的地址偏移量。
2.变量、变量定义伪指令
1)变量和标号 变量代表内存操作数的存储地址,或者说变量名 就代表某个存储单元。标号代表指令地址,它为 转移指令提供了转移目标。由于标号和变量是用 一串字符命名的,从这个意义上讲,标号和变量 又称为符号地址。标号和变量的命名规则是:以 字母或者下划线开头,后跟字母、数字、下划线, 长度不超过31个字符,并且系统中保留字不能作 为标号和变量名。保留字是系统中已经专用的有 特殊意义的名字,例如,指令的操作码助记符、 运算符、寄存器名称、伪指令助记符等等。
标号被定义在代码段,变量通常被定义在数据 段、附加段或堆栈段。 标号和变量都有共同的3个属性。即: a.段属性。即标号或变量所在段的段基址,用 SEG运算符可以计算得到。 b.偏移属性。即标号或变量所代表的存储单元, 相对于段首址之间的地址偏移量(又称有效地 址),用OFFSET运算符可以计算得到。
⑤ SIZE运算符 格式:SIZE 变量名
功能:计算一个存储区域所占用的字节数。
(5)综合运算符
ASM中,综合运算符有PTR和THIS。
THIS综合运算符的功能是改变存储区的类型,THIS 运算符也被称为类型指定运算符。THIS运算符的运 算对象是数据类型(BYTE、WORD、DWORD)或 者距离类型(NEAR、FAR),用于规定所指变量或 者标号类型属性或者距离属性。
汇编语言——宏

【例7.14】形式参数还可以出现在变量定义伪操作的初值表 中,甚至是以字符串形式出现的初值。 msg MACRO num,pname 'HELLO, &pname'
var&num DB ENDM
汇编语言规定,字符串中的形参必须用分隔符“&”从其它 部分分离出来。对于下面两个宏调用, msg msg 1,John 2,Henrry
code
ENDS END main
【解】宏展开后的结果是: + + + + + + MOV MOV INT MOV MOV INT MOV INT AH,2 DL, '*' 21H AH,2 DL, '*' 21H AH,4CH 21H
由于宏展开是汇编程序翻译的一个步骤,宏展后的结果 并不是源程序,所以展开后不再写出完整的程序格式,只列 出有效指令部分。 可以看到,汇编程序对宏调用与已定义的常量及符号的 引用的处理是很类似的,定义部分在汇编处理结束后就已完 成它的作用。汇编程序翻译后得到的机器代码中没有宏、常 量等的定义,只是调用或引用部分被代换成宏体或定义的内 容。宏与常量定义及符号定义的差别在于,常量及符号定义 都必须在一行写完,对常量和符号的引用只能代换指令中的 操作数,或者操作数的一部分,宏调用则可以代换一段程序。 不仅如此,宏还允许代换的内容有个别地方不同,这是通过 带参数的宏实现的。
(3)宏定义仅仅用来告诉汇编程序,将来宏调用时复制 的对象是什么,宏定义中的程序段并不是程序的一部分,也 就是说,如果程序中定义了一个宏而没有调用它,汇编程序 将忽略宏定义。 (4)宏定义可以写在程序的任何地方,但习惯上总是把 宏定义写在程序的最前面。 宏定义与编辑器中的文字块的定义有相似之处,也有一 些差别。两者都需要以特定的方式说明开始和结束的位置。 文字块是文件的一部分,而宏体中的程序段必须经过宏调用 才能复制到源程序中正确的位置,没有被调用的宏体在汇编 程序翻译时会被忽略。
04宏汇编语言

• 例如: • MOV DS:[BX],12H ;错误 • 因为无法指明操作数的长度类型。
• PTR临时修改变量名的属性 • 类似地,任何一条指令也必须明确变量名或 标号的类型。 • 变量名具有默认的类型属性。例如,使用 DB ABC定义:变量名ABC为字节类型,那么: • MOV DS:[ABC],12H ;正确
字节定义伪指令
• • • • • • • • 格式:[变量名] DB 一串用逗号间隔的单字节数 例如: BUF1 DB 55,66H,7*7 DB ?,? COUNT1 EQU $ - BUF1 ;COUNT1为? BUF2 DB 10 DUP(12H, 2 DUP (12, 34)) COUNT2 EQU $ - BUF2 ;COUNT2为? ①DB是Define Byte的缩写,DB伪指令的功能是通 知汇编程序,把所定义的单字节数转换成二进制数, 并从指定的变量单元开始依次存放。用DB伪指令定 义的这些单元的属性为“字节型”。
•
• •
•
• PTR指定存储器操作数长度 明确变量的长度类型十分重要。汇编语言规 定:任何一条指令必须明确内存操作数的长 度类型! 使用PTR指定存储器操作数长度的情况: 1、在单操作数指令中,该操作数为存储器操 作数(非变量名)时; 2、双操作数指令:当源操作数为立即数,目 的操作数为存储器操作数(非变量名)时;
• PTR临时修改标号或子程序名的类型属性 • 关于标号或子程序名的类型属性:由于各种 符号名不允许重名,编译程序能够自动识别 标号的类型属性。 • 程序中根据需要,仍然可以使用PTR临时修 改段内/段间的属性。
• 理解:对于一个NEAR型的标号ABC,仍然 可以使用如下指令: • JMP FAR PTR ABC ; (已验证!)
汇编语言——宏

因此,对这一类错误提示,程序员只能自己按规则进行宏展 开,并判断展开后的结果是如何出的错。对于MASM汇编程 序比较熟悉的人,还可以借助于MASM处理源程序时产生的 一个.LST文件(只要在MASM提问“Source listing[NUL.LST]” 时输入一个合适的文件名即可产生清单文件),判断程序中 的错误,以及查看宏展开的结果。 另外,宏调用的优先级高于其它伪指令和指令,所以如 果用伪指令或指令助记符等内部保留字作为宏的名字,则汇 编程序会把这样的标识符当作宏进行处理,而使得源程序中 无法使用其原有的功能。汇编语言中还提供了一个PURGE伪 指令,用于在源程序适当的位置取消某个宏。比如:
code
Байду номын сангаас
ENDS END main
【解】宏展开后的结果是: + + + + + + MOV MOV INT MOV MOV INT MOV INT AH,2 DL, '*' 21H AH,2 DL, '*' 21H AH,4CH 21H
由于宏展开是汇编程序翻译的一个步骤,宏展后的结果 并不是源程序,所以展开后不再写出完整的程序格式,只列 出有效指令部分。 可以看到,汇编程序对宏调用与已定义的常量及符号的 引用的处理是很类似的,定义部分在汇编处理结束后就已完 成它的作用。汇编程序翻译后得到的机器代码中没有宏、常 量等的定义,只是调用或引用部分被代换成宏体或定义的内 容。宏与常量定义及符号定义的差别在于,常量及符号定义 都必须在一行写完,对常量和符号的引用只能代换指令中的 操作数,或者操作数的一部分,宏调用则可以代换一段程序。 不仅如此,宏还允许代换的内容有个别地方不同,这是通过 带参数的宏实现的。
【例7.16】设有如下宏定义: sum MACRO a,b LOCAL next MOV CX,a LEA BX,b XOR AX,AX next:ADD AX,[BX] ADD ENDM 并已知buf1和buf2是已定义的两个变量,展开下面的宏调用: sum 5,buf1 sum 7,buf2 BX,2 LOOP next
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
【例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 宏
程序中使用宏分为定义和调用两个部分。宏定义用来说
明哪些指令或伪指令是将在程序中重复出现的程序段;宏调