




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第13章 高级宏汇编语言技术 13.1 结构 结构(structures)是IBM_PC机宏汇编程序MASM最具特色的功能,它允许提供颇有价值的编程环境。它直接引用了某些高级程序设计语言的结构数据的概念。 结构就是把逻辑上具有相互关联的一组数据,以某种形式组合在一起。如果在一个程序段中,需要多次使用相同的一组数据格式,那我们就可以把这一组数据格式定义为一个结构。例如,为了建造学生的学籍档案,只须确定一名学生的学籍档案的数据格式,比如,使用几个字节记录相关科目的考试成绩等项目。这个数据格式本身并不需要占据内存单元。它仅在一旦确定了为某个班(如该班有40名学生)建立档案时,就可以按照事先定义的结构
2、格式,在存储单元中布局40个相同的数据格式。这就是,当引用该结构时,它就会与存储器中的特定区域发生联系。 请读者注意:在程序中使用结构数据,必须对结构先定义,然后进行结构数据的预置与存储分配。只有这样才能对结构中各相关数据进行存取、修改和操作。 13.1.1 结构的定义 要在程序段中引用结构,必须先使用结构伪指令先定义。结构伪指令的使用格式为: 结构名 STRUC 结构名 ENDS其中,“结构名”不能缺省,且在同一个源程序中必须是唯一的。“数据定义语句序列”是用DB、DW或DD定义结构中各字段(Fields),这些语句中的变量名称叫做结构字段名。 每一个结构字段名都有局部偏移量及其类型的属性。
3、局部偏移量是指结构字段的第一个字节与结构起点之间的字节数,类型仍然是指字节、字或双字。【例131】定义一个结构 STRDAT STRUC DA1 DB ? DA2 DB 33H DA3 DW 10H DUP(?) DA4 DW BUFF ;可用字符作为结构字段的初值 DA5 DB ABCD STRDAT ENDS 结构定义中的DA1,DA2,DA3,DA4,DA5分别是结构STRDAT的结构字段名,它们的局部偏移量分别是0,1,2,22H,24H。这里,对局部偏移量的确定与数据段中的变量所代表的偏移量计算方法相同。结构中各字段可以指定具体的数值或字符作为结构字段的初值。用伪指令STRUC/EN
4、DS定义的结构,不产生目标代码,因而也没有分配存储单元。这是与数据段中的数据定义不同之处。 13.1.2 结构的预置与存储单元的分配 当结构定义后,我们可在程序中直接引用结构名,为结构预置副本,设置结构变量,分配存储空间。结构变量预置语句的格式为: 结构变量名 结构名 其中,“结构名”是已用STRUC/ENDS伪指令定义结构时的结构名。“结构变量名”是结构副本的标识符,它和其它变量一样也都具有三个属性:段属性、偏移属性和类型属性。段与偏移属性体现结构变量的地址,类型属性是表示结构的总字节数。 是为结构副本中的各字段进行预置。结构的预置既可以保留所有字段的初值,也可以修改某些字段的初值,无论对字
5、段的初值是否进行过修改,结构名后头的尖括号都是不能省略的。 【例132】对【例131】的结构进行引用的例子,即对结构的预置。 STR1 STRDAT STR2 STRDAT STR3 STRDAT STR4 STRDAT 10H DUP()在本例的结构预置中:结构变量名STR1对结构中所有字段都不加修改,保留各字段的初值;结构变量名STR2仅修改第一字段,其它各字段仍保留其初值;结构变量名STR3除了第三个字段(字段名为DA3)外,其余字段均进行了修改。结构变量名STR4对字段名为DA3中同时预置16个结构副本所进行的修改。 按【例132】的结构预置,结构变量STR1,STR2和STR3的存储
6、空间分配情况如图131所示的结构变量预置与存储单元的分配情况。 对结构字段初值的修改,并非所有字段中的初值都是可以修改的,只有简单结构字段和字符串字段的初值才可以修改。所谓简单结构字段就是由伪指令DB、DW或DD定义的单项变量,如【例131】中的结构 STRDAT内DA1,DA2,DA4就是只有单项的简单结构字段。而DA5是用DB伪指令定义的字符串,也可以用其它字符串进行修改。而存在多项(多重)变量的结构字段初值如【例131】中的DA3不能修改。具有多项或多重的结构字段,如由以下形式所示: DB 20H DUP(?) DW 34H,5678H,1234H DB 1234,ABCD DW COU
7、T,BUFF结构变量名的STR4同时预置16个结构副本。每一个副本中都是仅修改第一个字段初值,其余保留不变。这16个结构数据在分配存储空间时,将会依次存储。 ;结构变量预置DATA SEGMENT ;结构变量预置数据段 STRD1 STRDSS STRD2 STRDSS DATA ENDS 本例结构预置时,有两个结构字段是字符串。通常希望预置的字符个数与字段初值的个数相同。若预置的字符个数少于初值的个数,那么汇编程序将用“空格”填充右边的空间;若预置的字符个数多于初值的个数,则汇编程序将给出错误的信息。 13.1.3 结构变量及字段的操作 结构变量与一般变量一样,可做为指令的操作数,但使用某些
8、运算符时有不同的含意。当结构变量前面使用运算符时,运算符TYPE所表示的是结构所占的总字节数。其它运算符,如OFFSET ,LENGTH ,SIZE等所表示的意义与一般变量的使用相同。 【例134】针对【例133】的结构定义和预置,以下是每条指令汇编结果的示例(假设每条指令都为单独指令)。MOV AX,OFFSET STRD1 ;AX=0MOV AX, OFFSET STRD2 ;AX=1AH ;按结构定义的字节数定偏移量MOV BX, TYPE STRD1 ;BX=1AH ;是结构变量所占的总字节数MOV BX, TYPE STRD2 ;BX=1AHMOV CX, LENGTH STRD1
9、;CX=1MOV CX, LENGTH STRD2 ;CX=1MOV DX, SIZE STRD1 ;DX=1AH*1MOV DX, SIZE STRD2 ;DX=1AH*1为了访问结构变量中某些结构字段名,需要使用结构字段运算符“” ,该运算符的使用格式为:结构变量名. 结构字段名例如:STRD1.CLASS ;表示结构变量STRD1中的CLASS字段 STRD2.NUM ;表示结构变量STRD2中的NUM字段在“结构变量”字段名前添加运算符与一般变量名之前添加运算符有相同含义。如根据【例133】的结构定义和预置具有以下的结果: MOV SI,OFFSET STRD1.NUM ; SI=0A
10、H MOV CX,TYPE STRD1.CLASS ; CX=1 MOV CX,TYPE STRD2.NUM ; CX=1把结构变量STRD2的CLASS字段的第一个字符传送给AL,可使用以下指令序列: MOV BX, OFFSET STRD2 MOV AL, BX.CLASS或 MOV AL, STRD2.CLASS13.1.4 结构程序举例【例135】 已知结构定义为: SUM STRUC DA1 DW ? DA2 DB 6 DUP(?) SUM ENDS 编写程序,使用结构名称SUM作为操作符定义一个结构变量SUM-VAR,并将这个变量中DA2字段的6个字节无符号二进制数相加,将和存放在
11、这个结构变量的DA1字段里。其实现程序如下: DATA SEGMENT SUM STRUC DA1 DW ? DA2 DB 6 DUP(?)SUM ENDS SUM-VAR SUM NUM DB 22,33,44,55,66,77DATA ENDSCODE SEGMENT ASSUME CS:CODE, DS:DATA START: MOV AX,DATA MOV DS,AX MOV CX,6 MOV SI,0 LL: MOV AL,NUMSI MOV SUM-VAR.DA2SI,AL INC SI LOOP LL MOV CX,6 MOV SI,0 MOV AX,0 LLL:ADD AL,S
12、UM-VAR.DA2SI ;求和 ADC AH,0 INC SI LOOP LLL MOV SUM-VAR.DA1,AX ;存和 ;此处程序略 MOV AH,4CH INT 21H CODE ENDS END START 说明:虽然本例子只是一个很简单的例子,主要意图是用来体会结构的用法。比如,对结构变量中的简单字段和多重字段如何实现访问的问题。若要进一步了解结构的应用,读者可参阅有关书籍。 13.2 记录 记录(RECORD)与结构相似。结构是以字节作为基本单位来组成字段,而记录是以二进制数的位作为基本单位组成字段。在程序的编写中,对于记录的应用,也像结构一样,首先进行记录的定义,然后对记录
13、变量进行预置和存储分配,其后就可以在程序中对记录变量及其字段进行具体的操作。 13.2.1 记录的定义 一个记录定义可用于规定一个字节或一个字的格式,可以对记录中的每一字段进行命名,并且可以给它分配一个长度(位数),同时还可以对字段进行预置。和结构定义一样,记录定义的本身不进行存储分配,但是可以用记录名称作为汇编期间的操作符(伪指令),去预置任意多个8位或16位的记录,并为它分配存储单元。 记录定义伪指令的格式如下: 记录名 RECORD 字段名:宽度=表达式,字段名:宽度=表达式, 其中: (1) RECORD 是记录定义的伪指令保留字 (2) 记录名和字段名是一个标识符(符号名),它不能与
14、其它标识符同名,且不能缺省。 (3) 在字段名和宽度(表达式)之间必须有冒号“:”隔开。宽度是指所在字段规定的二进制位数。表达式是对字段设置的初值,它是任选项,但必须是该字段宽度所能表达的正整数。如果宽度7,表达式可以使用单引号括起来的字符。一个记录可以由若干个字段构成,但是所有字段宽度之和应16。若所有字段的宽度之和8,汇编程序自动把记录定义为字节(8位),否则定义为字(16位)。第一个定义的字段,总是安排在记录的高位,随后定义的各字段依照顺序向较低位安排。若各字段宽度之和小于8 或小于16,则将字节或字的各字段向右对齐(即最低位对齐),其余未用的高位数位以“0”填充。例如:RECD1 RE
15、CORD F1:4,F2:2,F3:6,F4:4 ;字段宽度之和16RECD2 RECORD E1:2,E2:4,E3:1,E4:1 ;字段宽度之和8RECD3 RECORD D1:3,D2:4,D3:3,D4:3 ;字段宽度之和小于16RECD4 RECORD C1:3=3,C2:2=2,C3:1=1 ;字段宽度之和小于8 RECD1记录的字段F1为4位,F2为2位,F3为6 位,F4为4 位,故记录正好为16位。没有未定义的数位,初始值为0。如图132所示。 MOV BL,WIDTH E1 ;BL=02H MOV CH,WIDTH RECD3 ;CH=0DH MOV CL,WIDTH D2
16、 ;CL=04H 2移位值运算 在源程序的编程语句中,可把“记录字段名”作为一个操作数直接引用,这时候便会返回一个常数。这个常数表示该字段右移到所在记录的最右边的移位次数。它也表明该字段在记录中的起始位置(从右到左的位次排列为015)。 例如,下列各语句是直接引用记录RECD1中各个记录中字段名的结果是:MOV AL,F1 ;AL=0CHMOV AH,F2 ;AH=0AHMOV BL,F3 ;BL=04HMOV BH,F4 ;BH=00H 3记录屏蔽运算符 格式:MASK 记录字段名 如果在记录字段名前头加上MASK运算符后,可以得到该“记录字段名”在记录中的屏蔽码,此时该字段的各位均为1,而
17、记录中其它各位的值均为0的代码。例如:MOV BX,MASK F1 ;BX=0F000HMOV CL,MASK E2 ;CL=3CHMOV DX,MASK D3 ;DX=0038HMOV CH,MASK C1 ;CH=38H 对记录及其字段的操作对记录变量的操作 对记录进行预置后,与一般的变量存取操作一样,记录变量可以在程序中进行任意的存取操作。例如:MOV AX,R1 ;取出记录变量R1的 0BF89H存入AX寄存器MOV BL,R2 ;取出记录变量R2 的63H存入BL寄存器 2对记录操作数的操作 在编写程序中,我们可以直接引用已经定义的记录名,作为一个记录操作数。记录操作数可以指定各字段
18、的新值,也可以保留字段的初值。记录操作数与记录变量是不同的。前者为常数,后者是已存入存储器中的数据。以下是对记录操作数所进行的操作。MOV AX,RECD1 ;AX=0CFB9HMOV BL,RECD4 ;BL=20HMOV BH,RECD4 ;BH=25H原记录初值MOV CL,RECD4 RECD4 ;把20H+25H值送入CL对记录字段的操作由于记录变量中的记录字段是由字或字节当中的某几位构成,因而不能像结构变量中的字段那样可以独立存取。记录变量中的字段存取,都要通过对记录变量的存取来实现,为便于处理字段,通常是把取出的字段放在寄存器或存储单元的最右边。例如,要把记录变量R1的F1和F2
19、字段取出,可以分别编写以下两个程序段:截取F1字段的程序段:MOV AX,R1 ;取出记录变量MOV CL,F1 ;F1字段移位值送CLSHR AX,CL ;F1字段移至AX的最右边提取F2字段的程序段:MOV AX,R1 ;取出记录变量AND AX,MASK F2 ;用F2屏蔽码分离出F2字段MOV CL,F2 ;F2字段移位值送CLSHR AX,CL ;F2字段移至最右边 倘若要对某个字段进行修改,那么可仿效上述方法取出字段,根据修改的要求进行处理,最后再把修改好的字段存回原记录相应的字段中。例如,对于有如R3+2记录变量中的D2字段求反,可编制程序段如下:MOV AX,R3+2 ;取记录
20、变量NOT AX;求反AND AX,MASK D2 ;分离出字段D2MOV BX,R3+2 ;再次取记录变量AND BX,NOT MASK D2 ;去掉原有字段D2OR BX,AX ;修改字段D2MOV R3+2,BX ;送入记录变量但如果改用异或指令XOR,则上述程序段可以用一条指令就可以实现:XOR R3+2,MASK D2 13.3 宏汇编 第11章介绍了使用子程序结构的程序设计,已经了解到子程序结构具有很多优点:可以节省存储空间及程序设计所花的时间;可以为模块化程序设计提供了条件;便于程序的调试及修改等。但是使用子程序也存在一些缺点:为转子及返回,保护及恢复现场以及参数的传递等都要增加
21、程序所占用空间;为了执行这些操作都要花费额外的时间。这些都说明了使用子程序结构,使得程序设计实现模块化的优点与所要增加的额外存储空间和程序运行时间的开销。在某些情况下,特别是在子程序本身较短或者对占用存储空间及运行速度没有特殊要求,或者是需要传递的参数较多的情况下,使用宏汇编就更加有利而且灵活,有的功能是使用子程序设计很难做到的,宏汇编就有独到之处。如果在汇编语言源程序中,有的程序段在整个程序中要多次出现,这种出现有的可能是完全不修改的重复,有的可能是仅修改程序段中某些操作数字段,而程序段的功能并没有多大的变化。为了减少源程序中重复编写相同程序段的工作,我们可以采用宏定义方式编写程序段,供源程
22、序进行宏调用,在汇编时再进行宏展开。例如,在某源程序中需要多次用到回车换行的操作,我们可以为它定义一条宏指令: CRLF MACROMOV AH,2MOV DL,0AHINT 21HMOV DL,0DHINT 21HENDM 有了这个宏定义,源程序中需要用到回车换行时,就只需书写宏指令名CRLF(宏调用)。汇编程序将用它的目标代码,即上述程序段代码去替代宏指令名CRLF的位置(宏展开)。但在宏定义之处不产生目标代码。宏功能的使用,可以使汇编语言源程序更加清晰,易于阅读,简化重复程序段的编写,减少重复编写相同程序段时出错的可能性。使用起来更加灵活。 13.3.1 宏功能的使用过程 宏功能的使用过
23、程分为:宏定义、宏调用、宏展开。必须掌握“先定义,后调用”的基本原则。 1. 宏定义 使用宏功能,首先必须进行宏定义。用MACRO/ENDM伪指令进行宏定义。MACRO表示宏定义的开始,ENDM表示宏定义的结束,而且MACRO与ENDM必须成对出现。其格式有以下两种: (1)不带参数的宏定义: MACRO 宏体 ENDM (2)带参数的宏定义: MACRO 形参1,形参2, 宏体 ENDM 其中,宏体是由若干条指令语句所组成的程序段。宏名就是给该宏体中的程序段指定的一个符号名,也是宏指令语句中调用该宏体而直接引用的符号名。在同一个源程序中宏名必须是唯一的。请注意:在ENDM语句之前不写宏名,这
24、是与段定义、过程定义等不同的地方。 不带参数的宏定义:意味着每次宏调用时,宏体内各语句序列均不作任何修改。如上面的CRLF宏定义就是不带参数的。因此每次宏调用都不需要修改宏体。带参数的宏定义:宏定义用到的形式参数(或称形参、虚参、哑元)。每个形式参数之间用逗号分隔。有了形式参数,使得在宏体中程序段的某些部分,允许在宏调用时作适当的修改。在宏定义中,把允许修改的部分用形式参数表示,当宏调用时,就用相应的实在实数(简称实参)来取代。形参可以有多个,各个形参之间要用逗号相隔。例如对两个字节单元内容相互交换的程序段,使用宏定义:EXBYTE MACR0 X,YPUSH AX ;保护MOV AL,XXC
25、HG AL,Y MOV X,ALPOP AX ;恢复ENDM 其中X,Y是可以临时指定进行互相交换数据的二个字节存储单元的变量。在宏定义中X,Y为形参。 宏定义可以进行嵌套,这时,宏体中语句序列除指令语句,伪指令语句外,可以是另一个已经定义过的宏名。 2. 宏调用 经过宏定义之后,在源程序中的任意位置可以直接引用宏名,构成宏指令语句。宏名的引用,就是宏调用。它要求宏汇编程序把宏定义的程序段目标代码完整拷贝到调用之处。若此宏定义是带参数的,就把宏调用时的实参去替代对应的形参的位置。 宏调用的格式: (1)无参数宏调用:宏名 (2)带参数宏调用:宏名 实参1,实参2,例如: CRLF EXBYTE
26、 DA1,DA2 ;设DA1与DA2是已定义的字节变量 宏汇编程序(如MASM等)对带参数的宏调用,是用第一个实参替代第一个形参,第二个实参替代第二个形参,以此类推。一般来说,实参的个数应该和形参的个数相等,但汇编程序并不要求它们必须相等。若实参个数多于形参个数,则多余的实参不予考虑;若实参个数少于形参个数,则多余的形参作“空”处理。另外也应该注意:宏展开时用实参取代形参后,所得到的语句应该是有效的,不能违反语法规则,否则汇编程序无法汇编而显示出错误信息。 3. 宏展开 当宏汇编程序扫描到宏调用的宏指令语句时,宏汇编程序就把宏定义中宏体的程序段目标代码替换宏指令语句。若是带参数的宏调用,则同时
27、用相应的实参替代宏体中对应形参的位置,并对原有宏体代码作修改。 以下用一个实例来说明宏定义,宏调用和宏展开的全部过程。在宏展开中带“1”符号的指令,表示为宏汇编程序在宏展开时自动依次插入宏体的指令。宏定义本身不生成任何目标代码,宏指令语句亦即宏调用本身也不生成目标代码,它仅表示程序中宏调用出现的位置。 【例137】 宏定义中的宏体是两个字节的操作数相乘,得到的16位乘积存入结果的字存储单元,编写出宏定义、宏调用、宏展开的过程。 宏定义: MULT MACR0 X,Y,RESULT PUSH AXMOV AL,XIMUL YMOV RESULT,AXPOP AXENDM 宏调用: MULT DA
28、1,CL,ZBX MULT 120,BL,ARRAY 宏展开: 1 PUSH AX1 MOV AL,DA11 IMUL CL1 MOV ZBX,AX1 POP AX 1 PUSH AX1 MOV AL,1201 IMUL BL1 MOV ARRAY,AX1 POP AX 由于在宏定义时允许带形参,调用时可以用实参取代,这点功能就比子程序的调用强,这就使得宏汇编的使用增加了灵活性。而且实参可以是常数、寄存器、存储单元变量名以及用存储器的寻址方式能找到的地址或表达式等。而且实参还可以是指令的操作码或操作数的一部分等等。宏汇编的这一特性是子程序所不及的,但是,宏调用的工作方式和子程序调用的工作方式是
29、完全不同的。子程序是在程序执行期间由主程序调用的,它只占有它自身大小的一个空间;而宏调用则是在汇编期间展开的,每调用一次就把宏定义体展开一次,因而它占有空间与调用次数有关,调用的次数越多,则占有的存储空间也越大。用宏汇编可以免去执行时间上的额外开销,但若宏调用次数较多,则其存储空间上的开销也是应该考虑的因素。因而,要视具体情况来选择使用方案。一般说来,由于宏调用可能占用较大的空间,所以代码较长的功能段往往使用子程序而不用宏功能;但那些较短的且变元较多的功能段,使用宏功能就更为方便而又灵活。 【例138】形式参数可以是操作码、操作数等的例子。宏定义:FUN MACRO P1,P2,P3 MOV
30、AX,P1 P2 P3 ENDM宏调用: FUN BUFFER,INC,CX ;设BUFFER是已定义的字变量宏展开:1 MOV AX,BUFFER1 INC CX这种功能就比子程序调用强。13.3.2 连接符&和带空格或逗号的实参在程序设计中使用宏调用时,有时候一个实参中可能是由字符、空格或者逗号组成,如“WORD PTR DA_BYTE”。这时要把带空格或逗号的实参用尖括号“”括起来,以表示它是一个完整的单一的实参。【例139】进行移位操作的宏定义和宏调用:SHIFT MACRO VAR,REG,SHF,NUM,DESTMOV REG,VARMOV CL,NUMS&SHF REG,CLMO
31、V DEST,REGENDMDATA SEGMENTDA_BYTE DB 22HDA_WORD DW 1234HCONT DB 2,3DEST1 DB 10H DUP(?)DATA ENDS SHIFT DA_BYTE,AL,HL,CONT,DEST1 ;宏调用1 MOV AL,DA_BYTE1 MOV CL,CONT1 SHL AL,CL1 MOV DEST1,ALSHIFT DA_WORD,AX,AR,CONT+1,1 MOV AX,DA_WORD1 MOV CL,CONT+11 SAR AX,CL1 MOV WORD PTR DEST1+2,AX 上述宏定义中有一个“&”符号,它是一个连
32、接符号。如上面的“S&SHF”中SHF是一个形参,当宏调用时,形参SHF用HL或AR实参代替。这时,宏汇编程序把S与实参直接连接起来,构成SHL或SAR指令助记符。连接符号&允许在其前面或者后面出现形参。【例1310】连接符号&允许在其后面出现形参的例子。宏定义:FF MACRO P1JMP TA&P1ENDM宏调用:FF WORD_VAR宏展开:+ JMP TAWORD_VAR在这里,如果宏定义写为FF MACRO P1JMP TAP1ENDM 则在展开时,汇编程序把TAP1看作一个独立的标号,并不把TAP1中的P1作为形参来看待,所以,在TA与P1之间如果没有“&”连接符号,就不能得到预期
33、的结果。 【例1311】形参是ASCII串的情况宏定义:MSSG MACRO LAB,NUM,XYZLAB&NUM DB HELLO MR.&XYZENDM宏调用:MSSG MSG,1,TAYLOR宏展开:1 MSG1 DB HELLO MR.TALOR13.3.3 局部符号伪指令LOCAL 当一个宏定义中,存在有变量名或标号名。而且在同一个源程序中又被多次进行宏调用,如此,在宏汇编程序进行宏展开时,将会产生多个相同的变量名或标号名。这就违反了变量名和标号名在同一个源程序中必须唯一的要求,从而产生重复定义符号的汇编出错。为了解决宏展开时标识符的重复定义,避免出错,用局部符号伪指令LOCAL来解
34、决这个问题。其基本格式为: LOCAL 形式参数1,形式参数2,局部符号伪指令LOCAL仅可在宏定义中的宏体内使用。而且是在MACRO语句后的第一个语句,由它说明的形式参数是宏定义中的变量名或标号名,这些变量名或标号名在宏展开时,汇编程序将自动为LOCAL语句中的形式参数生成一个特殊符号,其范围为?0000?FFFFH的符号。并且用这些特殊符号代替宏体中的形式参数,这样就保证了在源程序中具有多次宏调用时生成的变量名或标号名的唯一性,这样就避免了符号重复定义的错误。 【例1312】某源程序要多次进行无符号整数的乘法运算,设两个乘数为字数据,乘积仍然为字数据: (MULT1)*(MULT2)MUL
35、T3以下用连续相加的办法编制一个宏定义MULT。在宏定义中有标号,因此使用LOCAL伪指令,使宏定义中的标号在宏展开的程序段中自动生成带?的特殊符号。源程序为: ;* * * * * 乘法运算的宏定义 * * * * * * * * * * *MULT MACRO MULT1,MULT2,MULT3 LOCAL LOP,EXIT1 ;形式参数是两个标号名 MOV DX,MULT1 MOV CX,MULT2 XOR AX,AX ;累加器清0 JCXZ EXIT1 ;乘数为0退出LOP: ADD AX,DX LOOP LOPEXIT1: MOV MULT3,AX ENDM ;* * * * 以下是
36、宏调用与宏展开的情况 * * * * * *DATA SEGMENTDA1 DW 28H,38HDA2 DW 22H,18HDA3 DW ?,?DATA ENDSSTAK SEGMENT STACK DW 20H DUP(?)STAK ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX MULT DA1,DA2,DA3 ;宏调用1 MOV DX,DA11 MOV CX,DA21 XOR AX,AX1 JCXZ ? 00011? 0000: ADD AX,DX1 LOOP ?00001? 0001: MOV DA3
37、,AX MULT DA1+2,DA2+2,DA3+2;宏调用1 MOV DX,DA1+21 MOV CX,DA2+21 XOR AX,AX1 JCXZ ? 00031? 0002: ADD AX,DX1 LOOP ?00021? 0003: MOV DA3+2,AX MOV AX,4C00H INT 21H CODE ENDS END START注意:LOCAL伪指令用在宏定义体内,而且它必须是宏定义伪指令MACRO后的第一条语句,在MACRO和LOCAL伪指令之间还不允许有注释和分号标志。 宏库的应用 有时花费许多精力编写了一些好的“宏”,希望这些“宏”能为较多的程序服务,不必每次在源程序中
38、重复编制一个宏定义,也可减少重复编写时的错误。这时可以把若干个宏定义组成一个宏库,以文件的形式供其它源程序调用。如在MACRO.LIB文件中包括有以下三个宏定义,其内容如下:;-MACR0 DEFINELIB-INDZH MACR0 MOV AH,01H INT 21H ENDM;-OUTZHC MACR0 ADDR MOV DX,OFFSET ADDR MOV AH,09H INT 21H ENDM;- MULT MACR0 MULT1,MULT2,MULT3 LOCAL LOP,EXIT1 MOV DX,MULT1 MOV CX,MULT2 XOR AX,AX JCXZ EXIT1LOP:
39、 ADD AX,DX LOOP LOPEXIT1:MOV MULT3,AX ENDM 当某个源程序需要调用MACROLIB文件中已定义的“宏”时,可在源程序中使用伪指令INCLUDE。其格式为: INCLUDE 文件名 宏汇编程序遇到一个INCLUDE伪指令时,便可打开它所指定的文件,并处理每一个宏定义的各个语句,直到处理完毕。这样,在源程序中若需要宏调用该文件中已含有的宏定义,那就如同在源程序中自己进行宏定义一样的方便。 【例1313】宏库应用的例子。TITLE EXAM_MACR0 LIB INCLUDE MACR0.LIBSTAK SEGMENT STACK DW 100 DUP(?)S
40、TAK ENDSDATA SEGMENTSTR1 DBINPUT CHAR:$STR2 DB 0DH,0AH,OUTPUT STRING:BUF DB 10H DUP( ),10,13,$DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATASTART: MOV AX,DATA MOV DS,AX OUTZHC STR1 ;字符串显示 MOV DI,OFFSET BUF MOV CX,10HLOP1:INDZH ;输入单字符 MOV DI,AL INC DI LOOP LOP1 OUTZHC STR2 OUTZHC BUF MOV AH,4CH INT 2HC
41、ODE ENDS END START 设已经建立了一个宏库MACRO.LIB如下所示:MOVDS MACRO MOV AX,DATA MOV DS,AX ENDM ;CRLF MACRO MOV AH,2 MOV DL,13 INT 21H MOV DL,10 INT 21H ENDM ; DISPO MACRO MOV AH,2 MOV DL, INT 21H INT 21H INT 21H INT 21H MOV DL,O INT 21H ENDM ;DISPK MACRO MOV AH,2 MOV DL,K INT 21H MOV DL,! INT 21H ENDM;STRING MAC
42、ROMOV AH,9LEA DX,STRG INT 21H ENDM ; DOSF MACRO MOV AH,4CH INT 21H ENDM ;CODES MACROCODE SEGMENT ASSUME CS:CODE,DS:DATA GO:ENDM ;JIESU MACROCODE ENDS END GO ENDM ;有了以上宏库文件MACRO.LIB,现编写完成:显示The is a Computer!后回车换行,又在5个空格后显示OK!的程序可以写成下列形式: INCLUDE MACRO.LIBDATA SEGMENTSTRI DB The is a Computer!$DATA E
43、NDSCODESMOVDSSTRING STRICRLFDISPODISPKDOSFJIESU 宏库的建立,可以为编写不同的源程序所共享,按各功能模块定义宏指令,在源程序中可利用宏调用编程,这样编写的汇编语言源程序已经与高级语言的编程类似。 13.4 重复汇编 有时汇编语言程序需要连续地重复完成相同的或者几乎完全相同的一组代码,这时可使用重复汇编。重复汇编(Repeat assembly)伪指令可以出现在宏定义中,也可以单独出现在源程序中。重复汇编是在程序汇编期间对某些语句序列进行重复的汇编,而不是在程序运行期间执行重复操作。重复汇编伪指令有以下三种:13.4.1 重复汇编伪操作 格式:REP
44、T 表达式 (重复块) ENDM 功能说明:其中,表达式的值用来确定重复块的重复汇编的次数,表达式中如包含外部或未定义的项,则汇编指示出错。 【例1314】重复汇编带例子。 M=0NUM=5REPT 5M=M+1DB NUM*MENDM 这些语句经过汇编后,把5,0AH,0FH,14H,19H分配给5个连续的字节单元中,它们等效于以下语句: DB 5,0AH,0FH,14H,19H 【例1315】把字符A到Z的ASCII码填入数组TABLE。CHAR=ATABLE LABEL BYTE ;定义TABLE为字节属性 REPT 26 DB CHARCHAR=CHAR+1 ENDM经汇编产生:1 D
45、B 41H1 DB 42H 1 DB 5AH 【例1316】用重复汇编可以在81个连续字节单元中存放一个九九表的数值:N=0 REPT 9N=N+1M=0 REPT 9M=M+1 DB M*N ENDM ENDM 13.4.2 不定次数的重复汇编伪操作格式:IRP 形参, (重复块) ENDM 功能说明:IRP与ENDM之间重复块的重复次数由实参的个数所确定。每次重复汇编语句序列时,用一个实参取代形参。第一次用实参1,第二次用实参2,直到实参使用完为止。实参表必须用尖括号括起来,它可以是常数、寄存器、符号、字符串等。 IRP和下面要讲到的IRPC都和REPT一样,不一定要用在宏定义中。 【例1
46、317】 对于【例1314】也可编写为:NUM=5 IRP M, DB NUM*M ENDM尖括号内的实参是常数。【例1318】尖括号内的实参是寄存器的例子。IRP REG,PUSH REGENDM汇编后得:1 PUSH AX1 PUSH BX 1 PUSH SP 13.4.3 IRPC不定重复字符伪操作格式:IRPC 形参,字符串(或)(重复块)ENDM功能说明:IRPC和IRP类似,字符串的长度规定了重复的次数。宏汇编程序将把重复块连续地重复汇编字符串长度规定的次数,并在每次重复时依次用字符串中的一个字符作为实参代替重复块中的形式参数。如果字符串含有空格、逗号等分隔符时,那字符串需要用一对
47、尖括号括起来;没有空格、逗号等分隔符的字符串不带引号。【例1319】不定重复字符串汇编的例子。IRPC X,012345678DB X+1ENDM汇编后:1 DB 11 DB 2 DB 81 DB 9【例1320】下面的重复块是实现从堆栈中依次将数据弹给AX,BX,CX和DX四个寄存器。IRPC P,ABCDPOP P&XENDM汇编后得:1 POP AX1 POP BX1 POP CX1 POP DX 13.5 条件汇编使用条件汇编(Conditional assembly)可以使宏汇编语言源程序中的某些部分在汇编期间按照给定条件使其产生目标代码或不产生目标代码。通常可在汇编语言源程序的任何
48、位置上出现条件汇编语句,但是大多数条件汇编是出现在宏定义中。如同重复汇编伪操作一样,条件汇编仅在宏汇编程序的汇编期间对条件进行判断,是进行汇编或不必汇编,而不是在程序执行期间进行判断。条件汇编语句的格式为:IF XX argument(表达式)程序段1(条件块1)ELSE程序段2(条件块2)ENDIF 其中XX表示条件,自变量必须在汇编程序第一遍扫视后就成为确定的数值(即表达式的值已可确定)。表达式的值表示条件,其值可为真(TRUE)或假(FALSE)。ELSE及程序段2为可任选部分。 当条件为真时,对程序段1进行汇编。此时如果存在ELSE及程序段2,则跳过不再进行汇编。 当条件为假时,对程序
49、段1就不再进行汇编,但如果有ELSE及程序段2,则对程序段2进行汇编,假如没有ELSE及程序段2,则跳过程序段1后往下继续汇编。 ENDIF为条件汇编的结束语句,它必须与IF XX配对使用。 条件汇编伪操作指令简介: (1) IF 表达式 功能说明:表达式的值不为0,表示为真,汇编程序段1。否则跳过。 (2) IFE 表达式 功能说明:表达式的值为0,表示为真,汇编程序段1,否则跳过。 (3) IFDEF 符号 功能说明:如果符号已经在程序中定义,或者已用EXTRN伪指令说明该符号是在外部定义的,则满足条件,汇编程序段1,否则跳过。 (4) IFNDEF 符号 功能说明:如果符号没有定义或没有
50、通过EXTRN说明为外部符号则满足条件,汇编程序段1,否则跳过程序段1。 (5) IFB 功能说明:变量为空格,条件为真,汇编程序段1,否则跳过。注意:变量要用尖括号括起来。 (6) IFNB 功能说明:变量不为空格,条件为真,汇编程序段1,否则跳过。 (7) IFIDN , 功能说明:如果字符串和字符串相同,则条件为真,汇编程序段1,否则跳过。 (8) IFDIF , 功能说明:如果字符串和字符串不相同,则条件为真,汇编程序段1,否则跳过。 条件伪操作可以用在宏定义体内,也可以用在宏定义体外,也允许进行多次嵌套。在IF与IFE的表达式中允许使用关系操作符GT、GE、EQ、NE、LT和LE。运
51、算结果的值为真或假。 【例1321】 宏指令MAX的功能是:把三个无符号数形参中的最大值放在AX中,而且使得形参数不同时,产生不同的程序段。 宏定义:MAX MACRO N,X,Y,Z LOCAL NEXT,DONE MOV AX,X IF N1 ;N1=0为假,转DONE IF N2 ;N2=0为假,转NEXT CMP AX,Z ;以下是N3时找最大数 JAE NEXT MOV AX,Z ENDIFNEXT:CMP AX,Y JAE DONE MOV AX,Y ENDIFDONE:ENDM宏调用: MAX 1,J MAX 2,J,K MAX 3,J,K,M 宏展开: MAX 1,J 1 MO
52、V AX,J 1 ? 0001: 1 MAX 2,J,K 1 MOV AX,J 1 ? 0002: 1 CMP AX,K 1 JAE ? 0003 1 MOV AX,K 1 ? 0003: 1 MAX 3,J,K,M 1 MOV AX,J 1 CMP AX,M 1 JAE ? 0004 1 MOV AX,M 1 ? 0004: CMP K,AX 1 JAE ?0005 1 MOV AX,K 1 ? 0005: 【例1322】 宏指令BRCH将产生一条转向Y的转移指令。当它相对于Y的距离小于等于127个字节时,产生一条段内直接短转移指令JMP SHORT Y;否则产生段内直接近转移指令JMP N
53、EAR PTR Y,Y所表示的偏移量必须小于该转移指令所在处的偏移量,为了使($Y)不会是负数。 宏定义: BRCH MACRO Y IF ($Y)LE 127 JMP SHORT Y ELSE JMP NEAR PTR Y ENDIF ENDM宏调用: BRCH宏展开:如Y与BRCH指令间的距离小于等于127时产生 1 JMP SHORT Y否则产生 1 JMP NEAR PTR Y本例的宏定义中已经使用了关系运算符,这在一些宏定义中会经常用到。【例1323】为能实现多种DOS系统功能调用,试用条件汇编编写一个宏定义,供源程序进行宏调用。问题说明:DOS系统功能调用的功能号必须存放在AH寄存
54、器中,而对于字符串输出与输入的9号和10号功能,还要求把字符串缓冲区的首地址偏移量存入DX寄存器中,这是功能调用所要求的入口参数。在宏定义中设:形式参数X代表功能号,当X为0时就退出宏定义;BUFFER代表缓冲区的首地址。以下介绍终止宏扩展的伪指令:伪指令语句格式:EXITM 语句说明:结束MACRO调用或重复操作,遇到该语句就退出扩展体,扩展体的剩余部分不再执行。源程序清单: DOSGLMACRO X,BUFFERIFE X ;X=0条件为真,汇编EXITM而终止EXITMENDIFIFDEF BUFFERLEA DX,BUFFERMOV AH,XINT 21HELSEMOV AH,XINT 21HENDIFENDM ;*DATASEGMENTSTRIDB INPUT STRING:$BUFFERDB 81,0,80 DUP(0) ;为10号功能设的空间DATAENDSSTAKSEGMENT STACKDW 100 DUP(0)STAKENDSCODESEGMENTASSUME CS:CODE
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030年中国镀硅钢卷行业运行状况及发展前景分析报告
- 2025-2030年中国锂电池铝塑膜行业运营状况及发展前景分析报告
- 2025-2030年中国铀资源产业运行动态及发展趋势分析报告
- 2025-2030年中国轻钢结构行业十三五规划及发展策略分析报告
- 2025-2030年中国航空保险行业市场深度调查及投资前景预测报告
- 2025-2030年中国羊毛衫市场十三五规划及发展趋势分析报告
- 2025-2030年中国稀释剂市场运行状况及前景趋势分析报告
- 2025山西省安全员《C证》考试题库
- 河北石油职业技术大学《舞弊审计》2023-2024学年第二学期期末试卷
- 2025年重庆市建筑安全员考试题库
- 人力资源外包合同范本
- 成人重症患者颅内压增高防控护理专家共识2024
- 110KV送出线路工程施工组织设计方案和对策
- 2024年青岛职业技术学院高职单招语文历年参考题库含答案解析
- 《职业道德与法治》开学第一课(导言)(课件)-【中职专用】中职思想政治《职业道德与法治》高效课堂课件+教案(高教版2023·基础模块)
- (正式版)JBT 10437-2024 电线电缆用可交联聚乙烯绝缘料
- PI形式发票范文模板
- 自动化物料编码规则
- 小学音乐教材分析
- 委托收款三方协议
- 黄冈市2021-2022高一上学期期末考试数学试题及答案
评论
0/150
提交评论