汇编语言程序设计(刘慧婷第3版)微课版 课件 第8、9章 子程序设计、宏汇编及其它高级伪操作_第1页
汇编语言程序设计(刘慧婷第3版)微课版 课件 第8、9章 子程序设计、宏汇编及其它高级伪操作_第2页
汇编语言程序设计(刘慧婷第3版)微课版 课件 第8、9章 子程序设计、宏汇编及其它高级伪操作_第3页
汇编语言程序设计(刘慧婷第3版)微课版 课件 第8、9章 子程序设计、宏汇编及其它高级伪操作_第4页
汇编语言程序设计(刘慧婷第3版)微课版 课件 第8、9章 子程序设计、宏汇编及其它高级伪操作_第5页
已阅读5页,还剩153页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第8章子程序设计

为了使程序结构更加清晰,把程序需要完成的任务分解为若干个子任务,把每个子任务设计成一个相对独立的程序,称为子程序,也称为过程。8.1子程序结构8.1.1子程序调用指令8.1.2过程定义与过程结构

8.1.3保护和恢复现场寄存器8.1.1子程序调用指令子程序定义:在模块化程序设计中,经常把程序中某些具有独立功能的部分编写成独立的程序模块,称为子程序。主程序通过CALL指令调用子程序。子程序执行完毕后通过RET指令回到主程序。(1)CALL调用指令格式:CALLDST操作:首先把下一条指令的地址(返回地址)压入堆栈保存,再把子程序的入口地址置入IP(CS)寄存器,以便实现转移。对于段内调用,只是向堆栈保存IP寄存器的值。对于段间调用,是先向堆栈保存CS寄存器的值,再向堆栈保存IP寄存器的值。(2)RET返回指令格式1:RET格式2:RETEXP操作:把堆栈里保存的返回地址送回IP(CS)寄存器,实现程序的返回。对于段内调用,弹出一个字到IP寄存器。对于段间调用,先弹出一个字到IP寄存器,再弹出一个字到CS寄存器。例8.1例8.1代码段1中的主程序A调用代码段2中的子程序B,程序B调用代码段2中的子程序C,调用关系如图8-1所示,堆栈情况如图8-2所示。 主程序A程序B程序C ………………CALLFARPTRBCALLNEARPTRCRET(IP=2000H,CS=3400H)(IP=1000H,CS=6200H)………… RET8.1.2过程定义与过程结构过程定义伪指令

Procedure_NamePROCAttribute┇Procedure_NameENDP如:

mainprocfar/near┇mainendp过程名是标识符,起到标号的作用,是子程序入口的符号地址。过程的属性可以是FAR或NEAR类型。对过程属性的确定原则是:NEAR为近,是段内调用。FAR类型为远,是跨段调用。如调用程序和子程序在同一代码段,则使用NEAR属性;如调用程序和子程序不在同一代码段,则使用FAR属性。主程序的过程定义属性应为FAR。

例8.2调用程序和子程序在同一个代码段,调用程序和子程序并列。 mainprocfar … callsubr… ret mainendp subrprocnear… ret subrendp调用程序和子程序在同一个代码段,调用程序和子程序相互嵌套。 mainprocfar … callsubr … ret subrprocnear … ret subrendp mainendp例8.3调用程序和子程序不在同一个代码段。 code1segment … mainprocfar … callsubr … ret mainendp code1ends … code2segment … callsubr … subrprocfar … ret subrendp code2ends8.1.3保存和恢复现场寄存器子程序调用CALL:首先将返回地址压栈,然后把子程序的入口地址送入IP/CS寄存器。子程序返回RET:将堆栈里保存的返回地址送回IP/CS寄存器。在子程序中对主程序的现场实施保护和恢复在进入子程序后,对将要使用的寄存器,先保存这些寄存器的值,在子程序退出前恢复这些寄存器的值。保存和恢复寄存器

8.2子程序的参数传递入口参数(调用参数):主程序传递给子程序。出口参数(返回参数):子程序返回给主程序。传递的参数:值传递和地址传递。8.2.1用寄存器传递参数

用寄存器传递参数就是约定某些寄存器存放将要传递的参数。该方法简单,执行的速度也很快。但由于寄存器数量有限,不能用于传递很多的参数。例8.4从键盘输入一个十进制数(小于65536的正数),显示输出该数的十六进制形式。通过寄存器传送变量。算法分析1.输入的十进制数整合成二进制数;

2.整合的方法A(n)=A(n-1)*10+B(n);

3.二进制数转化为十六进制显示。程序结构框图DTOB子程序流程图 dtohexsegment assumecs:dtohex mainprocfar pushds xorax,ax pushax calldtob;十进制数键盘输入整合为二进制 callcrlf;输出回车换行 callbtoh;二进制转为十六进制显示

ret mainendp dtobprocnear movbx,0 input:movah,1;键盘输入

int21h subal,30h;把ascii码转变为数值 jlexit;如不是数则退出 cmpal,9 jgexit;如不是数则退出 cbw;扩展为字 xchgax,bx;交换寄存器 movcx,10 mulcx;a(n)=a(n-1)×10 addax,bx;a(n)=a(n)+b(n)xchgax,bx;交换寄存器 jmpinput exit:ret dtobendp btohprocnear movch,4;准备输出4位十六进制数 shift:movcl,4;每次需移4位 rolbx,cl moval,bl andal,0fh;取最右4位 addal,30h;转为ascii cmpal,39h jledig;是0~9则转dig addal,7;是A~F dig:movdl,al;显示 movah,2 int21h decch jnzshift ret btohendp crlfprocnear movdl,0dh movah,2 int21h movdl,0ah movah,2 int21h ret crlfendp dtohexends endmain讨论1.画出程序调用过程中堆栈的变化情况;2.画出DTOB,BTOH的程序流程图,并阐述算法思想;8.2.2用变量传递参数参数较多时可以用约定的变量在过程间传递参数。例8.5键盘输入字符串到缓冲区后,对缓冲区内容降序排序并输出。datasegment buffdb16;缓冲区大小 numbdb?;输入的字节数 arrydb16dup(?);缓冲区内容dataendscodesegment assumecs:code,ds:datamainprocfar pushds subax,ax pushax movax,data movds,ax callorder retmain endporderprocnear leadx,buff;输入缓冲区 movah,10 int21h movcl,numb;实际输入个数deccl movch,0lp1: movdi,cx movbx,0;下标lp2: moval,arry[bx]

cmpal,arry[bx+1] jgecont xchgal,arry[bx+1] movarry[bx],alcont:incbx decdi jnzlp2

looplp1 calloutput retorder endp;------------------outputprocnearmovbl,numb;后面插入$以便显示

movbh,0movbyteptr[arry+bx],'$'movdx,offsetarrymovah,9int21hretoutput endpcode endsendmain讨论1.画出降序排序的流程图,并简述算法思想;2.这两个例题是利用了寄存器和变量的什么性质,实现参数传递的?8.2.3用地址表传递参数的通用子程序在主程序中建立一个地址表,把要传递的参数地址放在地址表中,然后把地址表的首地址放入寄存器,子程序通过寄存器间接寻址方式从地址表中取得所需参数,可以设计通用子程序处理其他类似字符串排序问题。例8.6采用通过地址表传递参数地址的方法,键盘输入缓冲区并对其内容排序和输出。datasegment buffdb16 numbdb? arrydb16dup(?) tabledw3dup(?);地址表dataendscodesegment assumecs:code,ds:datamain procfar pushds subax,ax pushax movax,data movds,ax movtable,offsetbuff movtable+2,offsetnumb movtable+4,offsetarry movsi,offsettable;地址表首地址送si callorder retmainendporder procnear movdx,[si] movah,10 int21h movdi,[si+2] movcl,[di];实际输入个数送cxdeccl movch,0

lp1: movdi,cx movbx,[si+4];bx指向缓冲区lp2: moval,[bx] cmpal,[bx+1] jgecont xchgal,[bx+1] mov[bx],alcont:incbx decdi jnzlp2

looplp1 calloutput retorder endp;------------------outputprocnearmovdi,[si+2];后面插入$以便显示movbl,[di]movbh,0movdi,[si+4]movbyteptr[di+bx],'$'movdx,di movah,9int21hretoutput endpcode endsendmain思考题画出数据段中数据的存放情况,并用指针标注出数据之间的关系。为了实现在cx中存放字符串的实际长度,进行了几次寻址,每一次是什么寻址方式;为了实现每一轮中两个数的比较,对参与比较的两个数进行了几次寻址,每一次是什么寻址方式。8.2.4用堆栈传递参数的通用子程序用堆栈传递参数地址

,可以设计通用子程序。例8.7键盘输入缓冲区内容排序并输出,用堆栈传递参数地址。datasegment dw50dup(?);堆栈50个字 toslabelword;栈顶地址tos buffdb16 numbdb? arrydb16dup(?)dataendscodesegmentassumecs:code,ds:data,ss:datamainprocfar ;设置ss和sp movax,data movss,ax leasp,tos ;ds和0压入堆栈,以便返回dos pushds xorax,ax pushax movax,data movds,ax ;参数地址压入堆栈 leabx,buff pushbx;buff的地址压入堆栈 leabx,numb pushbx;numb的地址压入堆栈 leabx,arry pushbx;arry的地址压入堆栈 callorder retmainendporderprocnear movbp,sp movdx,[bp+6];buff地址送dx movah,10 int21h movdi,[bp+4];取numb的地址 movcl,[di]deccl movch,0;numb送cx

lp1: movdi,cx movbx,[bp+2];arry的地址送bxlp2:moval,[bx]

cmpal,[bx+1] jgecont xchgal,[bx+1] mov[bx],alcont:incbx decdi jnzlp2looplp2 calloutput ret6;修改sp指针并返回order endp;------------------outputprocnearmovdi,[bp+4];后面插入$以便显示movbl,[di]movbh,0 movdi,[bp+2]movbyteptr[di+bx],'$'movdx,di movah,9int21hretoutput endpcode endsendmain思考题程序初始时tos的值是多少?画出程序执行过程中,堆栈段中的存储情况8.2.5用结构变量传递参数的通用子程序结构就是把逻辑上互相关联的一组数据以某种形式组合在一起。在程序中,若要多次使用相同的一组数据格式,那么我们就可以把这一组数据格式定义为一个结构数据。结构类型的定义:结构名STRUC……结构名ENDSSTRUC伪指令只是定义了一种结构模式,还没有生成结构变量。用结构预置语句生成结构变量并赋值。结构预置语句格式:变量结构名<各字段赋值>对结构字段初值的修改,并非所有字段的初值都可以修改,只有简单结构字段和字符串字段初值才可以修改。简单结构字段是指由伪指令DB、DW或DD定义的单项变量。多项变量的结构字段初值不能修改。例如下面就是多项的结构字段:

DW10DUP(?)DB12H,34HDB‘ABCD’,’1234’例8.8定义一个名为STUDENT的结构类型。STUDENTSTRUCIDDB‘AAAAAAAA’NAMEDB3DUP(0)JF1DW22HJF2DW?JF3DW?JF4DW?STUDENTENDS例8.9结构变量预置语句(定义结构变量)STD1STUDENT<’A2031456’,,,33H>STD2STUDENT<>STDSSSTUDENT100DUP(<>)例8.10结构变量的访问

MOVSI,1LEABX,STD1MOVAL,STD1.NAME[SI];变量STD1的字段NAME的第2项送ALMOVAL,[BX].NAME[SI];变量STD1的字段NAME的第2项送ALMOVDL,STDSS+3*19.NAME[SI];变量STDSS第4条记录的字段NAME的第2项送AL例8.11键盘输入缓冲区内容排序并输出,用堆栈传递参数地址,使用结构类型.

datasegment dw50dup(?);堆栈50个字

toslabelword;栈顶地址tos buffdb16 numbdb? arrydw16dup(?)data endscode segment assumecs:code,ds:data,ss:datamain procfar ;设置ss和sp movax,data movss,ax leasp,tos ;ds和0压入堆栈,以便返回dos pushds xorax,ax pushax movax,data movds,ax ;参数地址压入堆栈 leabx,buff pushbx;buff的地址压入堆栈 leabx,numb pushbx;numb的地址压入堆栈

leabx,arry pushbx;arry的地址压入堆栈

callorder retmain endporderprocnear parstruc pipdw? p3dw? p2dw? p1dw? parends movbp,sp movdx,[bp].p1 ;buff的地址送dx movah,10 int21h movdi,[bp].p2;取numb的地址

movcl,[di] ;numb送cx decclmovch,0

lp1:movdi,cx movbx,[bp].p3;arry地址送bx lp2:moval,[bx] cmpal,[bx+1] jgecont xchgal,[bx+1] mov[bx],alcont:incbx decdi jnzlp2 looplp1calloutput ret6;修改sp指针并返回order endpcodeends endmain;------------------outputprocnearmovdi,[bp].p2movbl,[di]movbh,0movdi,[bp].p3movbyteptr[di+bx],'$'movdx,di movah,9int21hretoutput endpcode endsendmain思考题画出执行指令callorder后,堆栈段中的数据存储情况。8.3多模块程序设计

多模块程序设计中,各个模块独立编写,分别汇编,便于程序的编写,调试和维护。8.3.1多模块之间的参数传递局部符号和外部符号在本模块中定义,又只在本模块中引用的符号叫局部符号。

在本模块中定义,而在另一模块中引用的符号叫外部符号。对于外部符号,编程时需要明确说明。EXTRN符号名:类型[,…]

在另一个模块中定义而要在本模块中使用的符号必须使用EXTRN伪操作说明。符号名为变量时,则type应为BETY,WORD,DWORD等;如符号名为标号或过程名,则type应为NEAR或FAR。PUBLIC符号名1,符号名2,……

在一个模块中定义的符号(包括变量、标号、过程名等)在提供给其他模块使用时,必须要用PUBLIC定义。例8.12主程序键盘输入缓冲区,子程序对缓冲区内容排序并输出,采用独立模块。;812main.asmpublicbuff,numb,arryextrnorder:fardatasegment buffdb16 numbdb? arrydb16dup(?)dataendscodesegmentassumecs:code,ds:datamainprocfar pushds subax,ax pushax movax,data movds,ax leadx,buff movah,10 int21h callorder retmain endpcodeends endmain;812sub.asmpublicorderextrnbuff:byte,numb:byte,arry:bytecodesegmentassumecs:codeorderprocfar movcl,numb movch,0 movdi,cx lp1:movcx,di movbx,0 lp2:moval,arry[bx] cmpal,arry[bx+1] jgecont xchgal,arry[bx+1] movarry[bx],al cont:incbx looplp2 decdi jnzlp1 movbl,numb movbh,0 movbyteptr[arry+bx],'$' movdx,offsetarry movah,9 int21h retorder endpcode ends end各模块先分别汇编,然后再连接:Link812main+812subLink的次序影响结果,主模块在前面。codesegment assumeds:data,cs:codemainprocfar(1)(2)(3)………retmainendpcodeendsendmain此处添加题目描述MOVAX,DATAPUSHDSXORAX,AXPUSHAXABCD提交MOVDS,AXE多选题50分datasegmentdw100dup(?)toslabelworddataendscodesegment assume cs:code,ss:datamainprocfar()()()pushdsxorax,axpushaxcallfarptrsuba…;假定此处指令的地址为CS=3400h,IP=30h……codeendsendmain此处添加题目描述MOVAX,DATAMOVSS,AXMOVDS,AXMOVSP,TOSABCD提交LEASP,TOSE多选题50分编程题在数据段定义一个缓冲区在主程序中完成从键盘输入一个字符串到缓冲区,再从键盘输入单个字符;在查找子程序中查找缓冲区中该字符出现的次数;在显示子程序中把该字符出现的次数存入内存中并显示出来。8.3.2显示十进制数的通用模块例8.13从键盘输入一个十六进制数(不超过四位),显示输出该数的十进制形式。

算法分析:

1.输入的十六进制数转化为二进制数;

2.把二进制数用十进制显示;

3.辗转相除法。主程序文件HTODPRO.ASMextrnhtob:far,crlf:far,btod:farcodesegment assumecs:codemainprocfar pushds xorax,ax pushax callhtob callcrlf callbtod retmainendpcodeends endmain子程序文件htobpro.asmpublichtobcode1segment assumecs:code1htobprocfarstart:movbx,0;初始化 movch,4 movcl,4inchr:movah,1;键盘输入 int21h cmpal,30h jlexit ;非法输入 cmpal,39h jledig;输入是数字0~9 cmpal,41h jlexit;非法输入 cmpal,46h jgexit;非法输入 subal,37h;输入是大写A~F jmpls4dig: subal,30h ls4: shlbx,cl addbl,al decch jnzinchrexit: rethtobendpcode1endsend子程序文件btodpro.asmpublicbtodcode2segment assumecs:code2btodprocfar movcx,10000 callddiv movcx,1000 callddiv movcx,100 callddiv movcx,10 callddiv movcx,1 callddiv retbtod endpddivprocnear movax,bx movdx,0 divcx movbx,dx movdl,al adddl,30h movah,2 int21h retddiv endpcode2ends end子程序文件crlfpro.asmpubliccrlfcode3segment assumecs:code3crlfprocfar movdl,0ah movah,2 int21h movdl,0dh movah,2 int21h retcrlf endpcode3endsend8.3.3C语言程序调用汇编语言子程序汇编语言程序占用内存空间小,运行速度快,能够直接控制硬件。高级语言编写人机交互界面和数据分析处理程序比较方便。用高级语言编写主程序,汇编语言编写子程序。分别编译/汇编成目标文件。连接形成可执行文件。参数、调用和命名的规定(1)C语言通过堆栈向汇编语言传送参数。(2)C语言程序对外部过程须以EXTERN说明,在汇编语言子程序中必须在过程名前加下划线,并说明为PUBLIC。(3)C语言和汇编语言程序必须使用相同的存储模型。(4)汇编语言程序的返回参数放在AX寄存器(整型)。例8.14C语言程序调用汇编语言程序,求两个数中的较大数。/*主程序my_c.c*/externintmax(int,int);main(){intb; b=max(4,6);/*b=AX*/ printf("maxis%d",b);};------------------;子程序my_h.asm.modelsmallpublic_max.code_maxprocnear pushbp movbp,sp movax,[bp+4] cmpax,[bp+6] jgexit movax,[bp+6];AX寄存器中的最大值返回给C程序exit: popbp ret_maxendp end操作过程:1.对MY_H.ASM汇编:MASMMY_H/MX(加/MX是为了生成小写函数名,以适应C程序)2.在TC集成环境中,在菜单条上选择Option/Compiler/Model,在Model的选择窗口选项中选择所需要的存储模型,这里选small。编译MY_C.C程序。3.建立PRJ工程文件,文件内容为:MY_C.CMY_H.ASM在菜单条上选择Compile,并设立主文件为MY_C.C,然后选LINKEXEFILE。于是连接成EXE文件。在TC++集成环境中,设成.C文件也可以。第9章宏汇编及其它高级伪操作

宏汇编语言提供了类似于高级语言的某些复杂功能,如宏汇编、重复汇编与条件汇编,提高了使用汇编语言进行程序设计的质量和效率。9.1宏汇编宏是源程序中一段有独立功能的程序代码。它只需要在源程序中定义一次,就可以多次调用,调用时只需要用一个宏指令语句就可以了。宏功能既可以实现程序复用,又能方便的传递多个参数。子程序优点:省存储空间优化程序结构便于调试和修改子程序缺点:调用、返回、保存、恢复需花开销参数传递复杂因此,在程序较短,或需要传送的参数较多的情况下,用宏汇编更加有利。9.1.1宏定义、宏调用和宏展开宏定义:宏指令名MACRO[形参1,形参2,…]<宏定义体>ENDM宏定义体是一组有独立功能的程序代码。宏指令名给出宏定义的名称,调用时就使用宏指令名来调用宏定义。第一个符号必须是字符。哑元表给出了宏定义中所用到的形式参数,每个哑元之间用逗号隔开。宏调用:宏指令名[实参1,实参2,…]宏指令被定义后,在源程序中就可以直接调用,称为宏调用。一般说来,实参的个数应和形参的个数相等,但汇编程序并不要求它们必须相等。若实参个数大于形参个数,则多余的实参不予考虑,若实参个数小于形参个数,则多余的形参取空值。宏展开:在对源程序的汇编阶段,汇编程序对源程序中的每个宏调用都进行了宏展开,即用宏定义体取代源程序中宏指令名,用实参取代形参。应该注意,用实参取代形参后,所得到的语句应该是有效的,否则汇编程序将会指示出错。例9.1用宏指令实现两数的相加。宏定义:sumnMACROx,y,result movax,x

addax,y

movresult,ax ENDMsumnMACROx,y,result

movax,x

addax,y

movresult,ax

ENDM宏展开:1movax,341addax,251movbx,ax

宏调用:sumn34,25,bx

例9.2用宏指令实现两个八位有符号数的乘法。宏定义:imultiplyMACROx,y,result pushax moval,x

imuly

movresult,ax popax ENDM宏展开:1pushax1moval,cl1imuldl1mov[bx],ax1popax┇1pushax1moval,ary1imulvar1movsave,ax1popax宏调用:imultiplycl,dl,[bx]…imultiplyary,var,save例9.3某工厂工人的周工资由计时工资和计件工资组成,计时工资按每小时工资率RATE乘以工作小时数计算;计件工资按超定额部分乘以SUP计算(超定额=实际完成的工件数MADE-定额工件数PART),工资总额放在WAGE中。宏定义如下:

wagesmacrorate,hour,made,part,supwage=rate*hour+(made-part)*supendmrate=5part=100sup=4宏调用:wagesrate,40,120,part,sup宏展开为:wage=rate*40+(120-part)*sup从以上两个例子可以看出,子程序和宏指令具有类似的功能,但又有以下区别:空间的区别:宏指令并不节省目标程序的空间,而子程序在目标程序中只有一段;时间的区别:宏指令在运行时不需要其他额外的CPU开销,而子程序的调用、返回和保护现场、恢复现场需要占用时间;参数的区别:宏调用可实现多个参数的直接代换,方式简单灵活,而子程序参数传递麻烦。

9.1.2宏定义的嵌套这种嵌套结构的特点是外层宏定义的宏体中又有宏定义,只有调用外层宏定义一次后,才能调用内层宏指令。例9.4用嵌套的宏定义实现两个八位数的算术运算。宏定义:mathMACROmathname,action,nummathnameMACROx,y,result pushax movnum,x actiony movresultax popax ENDMENDM宏调用:

mathimultiply,imul,al宏展开:imultiplyMACROx,y,resultpushaxmoval,ximulymovresult,axpopax ENDM宏调用:

mathdivide,div,ax宏展开:divideMACROx,y,resultpushax movax,xdivy movresult,ax popax ENDM接下来可使用宏调用:divideary,var,save则宏展开如下:1pushax1movax,ary1divvar1movsave,ax1popax9.1.3宏定义中使用宏调用宏定义中使用的宏调用必须已经定义。例9.5用宏指令实现显示字符。宏定义:INT21MACROFUNCTN MOVAH,FUNCTN INT21H ENDMDISPCMACROCHAR MOVDL,CHAR INT212 ENDM宏调用:DISPC‘A’宏展开: 1MOVDL,‘A’ 2MOVAH,2 2INT21H这里的2表示第二层展开结果。9.1.4带间隔符的实参在宏调用中,有时实参使用的是字符串(不是单引号括起来的),而是字符串中包含间隔符(如空格、逗号等),为使间隔符成为实参的一部分,则要用尖括号将字符串括起来作为一个实参的整体来替换形参。例9.6在数据段中定义40个字节的存储空间。

defdbmacrobuf,xbufxendmdatasegmentdefdbarray,<db40dup(?)>dataends…宏展开为:

1arraydb40dup(?)

9.1.5连接操作符&用连接操作符&可连接实参,形成一个完整的符号或字符串。例9.7用操作符&连接实参,生成指令中的操作码。宏定义:shiftMACROrig,m,n movcl,n

s&mrig,cl

ENDMshiftMACROrig,m,n

movcl,n

s&mrig,cl

ENDM宏调用:shiftax,hl,4shiftdx,hr,2宏展开:1movcl,41shlax,cl1movcl,21shrdx,cl例9.8用操作符&连接实参,生成指令中的操作数。宏定义:studentmacrorec,n,name,tel recdb&n rec1db‘&name&,&tel’ rec2db‘&computer’ endmstudentmacrorec,n,name,tel

recdb&n

rec1db‘&name&,&tel’

rec2db‘&computer’

endm宏调用:

studentmsg,1,wang,12345678宏展开:1msgdb11rec1db‘wang,12345678’ 1rec2db‘&computer’

9.1.6宏替换操作符%宏替换:汇编程序把跟在%后的表达式的值转换为当前基数下的数,在展开期间用这个数来取代形参(哑元)。格式:%表达式例9.9用操作符%将实参的值替换形参。宏定义: studentmacrorec,n,msg rec&ndbmsg endm宏调用: n=1 studentnumb,%n,‘wang,12345678’ n=n+1 studentnumb,%n,‘zhou,56781234’9.1.7LOCAL伪操作在宏定义中,常常使用标号,当多次宏调用后,就会出现标号重复定义的错误。显然在程序中多次调用该宏定义时,则展开后会出现标号的多次重复定义,这是不允许的。为此,系统提供了LOCAL伪操作。例9.10宏定义体中使用标号。错误形式宏定义: cmpdatamacror1,r2,max cmpr1,r2 jgemr1 movmax,r2 jmpmr2 mr1:movmax,r1 mr2: endm宏调用: cmpdataax,bx,var cmpdatadx,cx,valueLOCAL伪操作格式:LOCAL符号[,符号]汇编程序对LOCAL伪操作定义的符号说明为局部标号,对每一个局部标号建立唯一的符号(用??0000~??FFFF)来代替每个局部标号。注意:LOCAL伪操作只能用在宏定义体内,而且必须是MACRO伪操作后的第一个语句。正确形式宏定义: cmpdatamacror1,r2,max localmr1,mr2 cmpr1,r2 jgemr1 movmax,r2 jmpmr2mr1:movmax,r1 mr2: endm宏调用: cmpdataax,bx,var cmpdatadx,cx,value宏展开:1cmpax,bx1jge??00001movvar,r21jmp??00011??0000:movvar,r11??0001:1cmpdx,cx1jge??00021movvar,r21jmp??00031??0002:movvar,r11??0003:9.1.8使用宏库文件如果程序中定义了多个宏,用户可以把它们集中建立在一个独立的宏库文件中。宏库文件为文本文件,扩展名可为MAC。用INCLUDE伪指令加入宏库文件,格式:INCLUDE宏库文件名宏库文件和当前源程序中定义的标识符不能重复。例9.11宏库文件STDIO.MAC是关于输入/输出的文件。内容如下: crequ13 lfequ10 getcharmacro movah,1 int21h endm putcharmacroasc movah,2 movdl,asc int21h endm printsmacromsg movah,9 movdx,offsetmsg int21h endm inputsmacroconbuf movah,10 movdx,offsetconbuf int21h endm crlfmacro putcharcr putcharlf endm exitmacro movah,4ch int21h endm例9.12在程序中加入宏库文件STDIO.MAC,并使用其中的宏指令。程序内容如下: includestdio.mac datasegment stringdb16,?,16dup(?) msgboxdb‘输入字符串请用$结束’,13,10,‘$’ dataends codesegmentassumecs:code,ds:data start: getchar;输入一个字符 crlf;输出回车换行 putchar‘a’;输出一个字符 crlf;输出回车换行 inputsstring;输入字符串 crlf;输出回车换行 printsstring+2;输出字符串 exit;退出程序codeends endstart下列程序是在3个数中找出最小的数并放入al,在括号中填入指令使其完整。

mov

al,x

mov

bl,y

mov

cl,z

cmp

al,bl (1)

(2)

l1:cmpal,cl(3)(4)

l2:ret空1的答案jll1xchgal,blxchgal,cljlel2ABCD提交单选题10分空2的答案jll1xchgal,blxchgal,cljlel2ABCD提交单选题10分空3的答案jll1xchgal,blxchgal,cljlel2ABCD提交单选题10分空4的答案jll1xchgal,blxchgal,cljlel2ABCD提交单选题10分数据段如下:datasegmentda1 db 1,2,‘abcd’

count=$-da1da2db9dup(?)dataends补充括号处的指令,使得程序把DA1数据区数据移到DA2数据区。mov ax,data

movds,axmov

es,(5)mov cx,(6)

mov

si,(7)

movdi,(8)(9)

(10)空5的答案OFFSETDA1AXCOUNTOFFSETDA2ABCD提交REPMOVSBECLDF单选题10分空6的答案OFFSETDA1AXCOUNTOFFSETDA2ABCD提交REPMOVSBECLDF单选题10分空7的答案OFFSETDA1AXCOUNTOFFSETDA2ABCD提交REPMOVSBECLDF单选题10分空8的答案OFFSETDA1AXCOUNTOFFSETDA2ABCD提交REPMOVSBECLDF单选题10分空9的答案OFFSETDA1AXCOUNTOFFSETDA2ABCD提交REPMOVSBECLDF单选题10分空10的答案OFFSETDA1AXCOUNTOFFSETDA2ABCD提交REPMOVSBECLDF单选题10分9.2其它高级伪操作9.2.1PURGE伪操作一个宏定义可以用PURGE伪操作来取消,然后可以再重新定义。格式:PURGE宏指令名[,宏指令名]取消宏定义的作用是使该宏定义成为空,如果程序中对已被取消宏定义进行宏调用,汇编程序则忽略该宏调用,不会进行宏展开。9.2.2列表伪操作列表伪操作可以控制其后的宏调用是否在列表文件中出现宏展开,并不影响宏展开的实际产生。.LISTMACRO\XALL:列出产生目标码的宏展开,默认情况。.LISTMACROALL\LALL:列出包括注释在内的所有宏展开。.NOLISTMACRO\SALL:不列出任何宏展开。9.2.3重复汇编有时程序中,需要得到连续相同的或者格式相同的一组代码,这时可使用重复汇编。1.重复伪操作格式:REPT表达式

…(重复块)

ENDM表达式的值表示重复块的重复次数。

例9.13在数据段产生字节数据,首地址为ARRAY。宏定义: X=0 ARRAYLABELBYTE REPT99 DBX X=X+1 ENDM汇编后产生: 1DB0 1DB1 1DB2… 1DB98例9.14在代码段产生一组代码,该组代码的功能是从键盘输入9个字符,放入数组ARRAY中。程序如下: n=0 rept9 getcharmovarray+n,aln=n+1endmmovah,4chint21hcodeendsendstart

getcharmacro movah,1 int21hendmdatasegmentarraydb10dup(?)dataendscodesegmentassumecs:code,ds:datastart:movax,data

movds,ax重复汇编中使用了宏调用,这部分经汇编后产生: 2movah,1 2int21h 1movarray+n,al 1n=n+1 2movah,1 2int21h 1movarray+n,al 1

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论