您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > 第四章-汇编语言程序设计-3
子程序设计子程序又称过程过程的定义和调用•过程的定义ProcedurenamePROCattribute…RETProcedurenameENDP过程名(Procedurename)是标识符•过程的调用CALL指令直接寻址方式间接寻址方式段内调用段间调用当过程和主程序在同一代码段时,过程定义和调用的格式如下:CSEGSEGMENTMAINPROCFAR…CALLSUBT…RETMAINENDPSUBTPROCNEAR…RETSUBTENDPCSEGENDS当过程和主程序不在一个代码段时,则过程的定义和调用格式如下:XSEGSEGMENTSUBT1PROCFAR…RETSUBT1ENDP…CALLSUBT1XSEGENDSYSEGSEGMENT…CALLSUBT1YSEGENDS寄存器内容的保护和恢复SUBRPPROCFARPUSHAXPUSHBXPUSHCXPUSHDX…POPDXPOPCXPOPBXPOPAXRETSUBPRENDP主程序和过程间的参数传送•用CPU内部的寄存器传送参数例:将4位十六进制ASCII码转换为等值二进制数,已知4位十六进制ASCII码存放在内存的某一区城中,且低位数的地址号低,而高位数的地址号高。将4位十六进制ASCII码转换为等值二进制数的过程为:从最低位ASCII码开始,逐位将一个字节的ASCII码转换为等值二进制数,最后将它们拼装起来即可。入口参数:存放4位十六进制ASCII码的内存首地址送入DS:SI,ASCII码的位数4存放在CL中。出口参数:转换结果(等值二进制数)存放在DX中。CSEGSEGMENTASSUMECS:CSEGASC_BINPROCFARPUSHAX;保护寄存器内容。MOVCH,CL;位数送CH。CLD;方向标志清零。XORAX,AX;AX及DX、清零。MOVDX,AXAGAIN:LODSB;(DS:SI)→AL,(SI)+1→SI。ANDAL,7FH;设置标志位。CMPAL,‘9’;判该位ASCII码是否大于39H。JGA_TO_FSUBAL,30HJMPSHORTROTATEA_TO_F:SUBAL,37HROTATE:ORDL,AL;拼装各位转换结果。RORDX,CLDECCHJNZAGAINPOPAXRETASC_BINENDPCSEGENDS调用程序:STACKSEGMENTDW256DUP(?)TOPLABELWORDSTACKENDSDATASEGMENTASC_STGDB4DUP(?)BIN_RESULTDW?DATAENDSXSEGSEGMENTASSUMECS:XSEG,DS:DATA,SS:STACKMAINPROCFARMOVAX,STACKMOVSS,AXMOVSP,OFFSETTOPSTART:PUSHDSSUBAX,AXPUSHAXMOVAX,DATAMOVDS,AXMOVSI,OFFSETASC_STGMOVCL,4CALLASC_BINMOVBIN_RESULT,DX…RETMAINENDPXSEGENDSENDSTART•指定内存单元(变量)传递参数。例:在某一程序中,若需对N元素的数组求和,便可设计一个属性为NEAR的过程,它用来完成数组N个元素的求和,过程如下:PROADDPROCNEARPUSHAXPUSHCXPUSHDXPUSHSILEASI,ARYMOVCX,COUNTXORAX,AXMOVDX,AXAGAIN:ADDAX,[SI];累加N个元素的低位字。JNCNEXTINCDX;若有进位,则和的高位字加1。NEXT:ADDSI,2LOOPAGAINMOVSUM,AXMOVSUM[2],DXPOPSIPOPDXPOPCXPOPAXRETPROADDENDS…CSEGENDP主程序如下:DSEGSEGMENTARYDW100DUP(?)COUNTDW?SUMDW2DUP(?)…DSEGENDSSSEGSEGMENTSTACKDB100DUP(?)TOPLEBELWORDSSEGENDSCSEGSEGMENT…CALLPROADD…•通过地址表传送变量地址以数组元素求和为例,过程定义如下:PROADDPROCNEARPUSHAXPUSHDXPUSHCXPUSHSIPUSHDIMOVSI,[BX];取数组地址。MOVDI,[BX+2];取元素个数,并送入CX。MOVCX,[DI]MOVDI,[BX+4];取和数地址。XORAX,AXMOVDX,AXNEXT:ADDAX,[SI]JNCNO_CARRYINCDXNO_CARRY:ADDSI,2LOOPNEXTMOV[DI],AXMOV[DI+2],DXPOPDIPOPSIPOPCXPOPDXPOPAXRETPROADDENDP…主程序如下:DSEGSEGMENTARY1DW100DUP(?)COUNT1DW?SUM1DW2DUP(?)NUMDW100DUP(?)NDW?TOTALDW2DUP(?)TABLEDW3DUP(?)DSEGENDSSTACKSEGMENTSTACKDB100DUP(?)TOPLABELWORDSTACKENDSCSEGSEGMENT…MOVAX,DSEGMOVDS,AX…MOVTABLE,OFFSETARY1;装填地址表。MOVTABLE[2],OFFSETCOUNT1MOVTABLE[4],OFFSETSUM1MOVBX,OFFSETTABLE;表地址存入BX。CALLNEARPTRPROADD;求数组ARY1的和。MOVTABLE,OFFSETNUM;重新建立地址表。MOVTABLE[2],OFFSETNMOVTABLE[4],OFFSETTOTALLEABX,TABLECALLNEARPTRPROADD;求数组NUM的和。CSEGENDS•用堆栈传送参数过程定义如下:PROADDPROCNEARPUSHBPMOVBP,SP;采用BP访问参数地址。PUSHAXPUSHDXPUSHCXPUSHSIPUSHDIMOVSI,[BP+8];取数组地址。MOVDI,[BP+6];取计数值地址。MOVCX,[DI];计数值送CX。MOVDI,[BP+4];和数地址送DI。XORAX,AX;AX及DX清零。MOVDX,AXNEXT:ADDAX,[SI]JNCNO-CARRYINCDXNO-CARRY:ADDSI,2LOOPNEXTMOV[DI],AXMOV[DI+2],DXPOPDIPOPSIPOPCXPOPDXPOPAXPOPBPRET6PROADDENDP……数组地址数组个数地址和数地址(IP)原BP(AX)(DX)(CX)(SI)(DI)…BP过程调用前及返回后的栈顶主程序如下:CSEGSEGMENTMOVBX,OFFSETARY1;参数地址压入堆栈。PUSHBXMOVBX,OFFSETCOUNT1PUSHBXMOVBX,OFFSETSUM1PUSHBXCALLNEARPTRPROADD…MOVBX,OFFSETNUM;参数地址压入堆栈。PUSHBXMOVBX,OFFSETNPUSHBXMOVBX,OFFSETTOTALPUSHBXCALLNEARPTRPROADDCSEGENDS过程的嵌套、递归调用和可重入性例:实现N!(N≥0):N!=N×(N-1)×(N-2)×…×1N!=N×(N-1)!N0N!=0!=1N=0设阶乘子程序为FACT(N),则求N阶乘的过程为N!=FACT(N)=N×FACT(N-1)=N×(N-1)×FACT(N-2)……=N×(N-1)×(N-2)×…×…FACT(0)DATASEGMENT;定义数据段。VAL-NDW?RESULTDW?DATAENDSSTACKSEGMENT;定义堆栈段。DW128DUP(0)TOPLABELWORDSTACKENDSCODE1SEGMENTMAINPROCFARASSUMECS:CODE1,DS:DATA,SS:STACKSTART:MOVAX,STACK;设置SS及SP。MOVSS,AXMOVSP,OFFSETTOPPUSHDS;将PSP中INT20H的首址压入堆栈SUBAX,AXPUSHAXMOVAX,DATAMOVDS,AXMOVBX,OFFSETRESULT;将运算结果的地址压入栈。PUSHBXMOVBX,VAL_N;将参量N压入栈PUSHBXCALLFARPTRFACT;递归调用FACT子程序。…RETMAINENDPCODE1ENDSCODESEGMENTFRAMESTRUC;定义结构数据模式。SAVE_BPDW?SAVE_CS_IPDW2DUP(?)NDW?RESULT_ADDRDW?FRAMEENDSASSUMECS:CODEFACTPROCFAR,PUSHBP;存BP。MOVBP,SP;BP作为帧指针。PUSHBX;保护寄存器内容。PUSHAXMOVBX,[BP].RESULT_ADDR;结果地址送BXMOVAX,[BP].N;取NCMPAX,0;N=0?JEDONEPUSHBX;下一次的结果地址入栈。DECAX;N-1压入栈。PUSHAXCALLFARPTRFACTMOVBX,[BP].RESULT_ADDR;结果地址送BX。MOVAX,[BX];上次的结果取入AX。MUL[BP].N;(AX)=N*RESULTJMPSHORTRETURNDONE:MOVAX,1;0!=1。RETURN:MOV[BX],AX;存最终结果。POPAXPOPBXPOPBPRET4FACTENDPCODEENDSENDSTART多模块程序设计优点:•适合集体分工合作•已编好的程序模块可被直接利用•维修和更改功能很方便。多模块的连接模块1DSEGSEGMENTCOMMONDW50DUP(?)DSEGENDCODESEGMENTPUBLIC…CODEENDS模块2DSEGSEGMENTCOMMONDW40DUP(?)DSEGENDCODESEGMENTPUBLIC…CODEENDS组合类型为COMMON和PUBLIC时的连接结果连接后的数据段连接后的代码段模块1的数据段模块2的数据段模块2的代码段模块1的数据段模块间标识符的交叉访问模块1EXTRNFIRST:BYTE,ADDITION:FAREXTRNSECOND,WORD,SUBTRACT:NEARPUBLICTABLE,DATADSEGSEGMENTPUBLIC‘DSEG’TABLEDB100DUP(?)DATADW?DSEGENDSCODESEGMENTPUBLIC‘CODE’ASSUMECS:CODE,DS:DSEG…MOVAX,DSEGMOVDS,AX…MOVAL,FIRST;FIRST的段地址在DS中。…MOVAX,SEGSECOND;SECOND的段地址在ES中。MOVES,AXMOVBX,ES:SECOND…CODEENDSEND模块2EXTRNTABLE:BYTE,THIRD:WORDPUBLICSUBTRACT,FIRSTDSEGSEGMENTPUBLIC‘DSEG’FIRSTDB?…DSEGENDSCODESEGMENTPUBLIC‘CODE’…SUBTRACT…CODEENDSEND模块3EXTRNDATA:WORDPUBLICADDITION,SECOND,SUMDSEG1SEGMENTSECONDDW?SUMDW?…DSEG1ENDSCSEGSEGMENT…ADDITNION:…CSEGENDSEND多模块程序的设计模块化程序设计的步骤如下:(1)正确地描述整个程序需要完成什么样的工作;(2)把整个工作划分成多个任务,并画出层次图,(3)确切地定义每个任务必须做什么事,它与其他任务之间如何进行通信,写出模块说明;(4)把每个任务写成汇编语言模块,并进行调试;(5)把各个模块连接在一起,经过凋试形成一个完整的程序;(6)把整个程序和它们的说明合在一起形成文件划分模块时应该遵循的一些原则:(1)模块之间的控制耦合应尽可能简单,应该尽量避免从多个入口点进入模块或从多个出口点退出。(2)模块之间的数
本文标题:第四章-汇编语言程序设计-3
链接地址:https://www.777doc.com/doc-3189652 .html