1第六章子程序结构§6.1子程序的设计方法§6.2嵌套与递归子程序§6.3子程序举例§6.4DOS系统功能调用2§6.1子程序的设计方法一、子程序指令二、子程序的调用与返回三、现场的保护与恢复四、子程序参数的传递3一、子程序指令子程序是完成特定功能的一段程序当主程序(调用程序)需要执行这个功能时,采用CALL调用指令转移到该子程序的起始处执行当运行完子程序功能后,采用RET返回指令回到主程序继续执行4一、子程序指令—调用指令CALL指令分成4种类型(类似JMP)CALLlabel;段内调用、直接寻址CALLr16/m16;段内调用、间接寻址CALLfarptrlabel;段间调用、直接寻址CALLfarptrmem;段间调用、间接寻址CALL指令需要保存返回地址:段内调用——偏移地址IP入栈SP←SP-2,SS:[SP]←IP段间调用——偏移地址IP和段地址CS入栈SP←SP-2,SS:[SP]←CSSP←SP-2,SS:[SP]←IP5一、子程序指令—返回指令根据段内和段间、有无参数,分成4种类型RET;无参数段内返回RETi16;有参数段内返回RET;无参数段间返回RETi16;有参数段间返回需要弹出CALL指令压入堆栈的返回地址段内返回——偏移地址IP出栈IP←SS:[SP],SP←SP+2段间返回——偏移地址IP和段地址CS出栈IP←SS:[SP],SP←SP+2CS←SS:[SP],SP←SP+26一、子程序指令—返回指令RET的参数RETi16;有参数返回RET指令可以带有一个立即数i16,则堆栈指针SP将增加,即SP←SP+i16这个特点使得程序可以方便地废除若干执行CALL指令以前入栈的参数7二、子程序的调用与返回CALLlabel主程序RET子程序回到CALL指令后的指令处——返回地址8二、子程序的调用与返回—书写形式(同一代码段内)9二、子程序的调用与返回—书写形式(不同代码段)10三、现场的保护与恢复现场:主程序转向子程序之前,其所使用的一些资源的状态(如标志位、R/M等)子程序与主程序分别编制,通常会导致使用的资源发生冲突而影响主程序在调用子程序之后的正确执行方法:利用堆栈在主程序中进行在子程序中进行11三、现场的保护与恢复—在主程序中进行……PUSHBXPUSHAXCALLSUB1POPAXPOPBX……注意:进栈/出栈的顺序保护与恢复的对象:主程序用到的存有数据、中间结果且在CALL指令后还要用到的R/M12三、现场的保护与恢复—在子程序中进行SUB1PROCPUSHBXPUSHAX……POPAXPOPBXRETSUB1ENDP注意:进栈/出栈的顺序保护与恢复的对象:子程序用到的R/M13四、子程序参数的传递入口参数(输入参数):主程序提供给子程序出口参数(输出参数):子程序返回给主程序参数的形式:①数据本身(传值)②数据的地址(传址)传递的方法:①寄存器②变量③堆栈14例:将两个给定的二进制数转换成为二进制数的ASCII码形式并加以显示对两个数进行转换、显示的工作是相同的,没有必要重复编写,以子程序的形式来完成显示子程序需被告知:被显示内容的起始位置被显示内容的长度被转换的数及其长度存放结果的起始位置转换子程序需被告知:15例:将两个给定的二进制数转换成为二进制数的ASCII码形式并加以显示(6-1-1.asm)方法一:用寄存器传递参数显示子程序:DI:被显示内容的起始位置指针CX:被显示内容的长度BX:被转换的数CX:被转换数的长度DI:存放结果的起始位置指针转换子程序:16;转换子程序BINASCPROCREP1:ROLBX,1MOVDL,BLANDDL,01HADDDL,30H;屏蔽除最低位外的其他位MOV[DI],DLINCDILOOPREP1RETBINASCENDPBLBHDLDI17;显示子程序DISPPROCREP2:MOVAH,2MOVDL,[DI]INT21HINCDILOOPREP2MOVDL,0AH;设置显示后的光标位置MOVAH,2INT21HMOVDL,0DHMOVAH,2INT21HRETDISPENDP18DSEGSEGMENTPARA'DATA'BIN1DB35HBIN2DW0AB48HASCBUFDB20HDUP(?)DSEGENDSCSEGSEGMENTPARA'CODE'ASSUMECS:CSEG,DS:DSEG,SS:SSEGMAINPROCFARMOVAX,DSEGMOVDS,AXMOVBH,BIN1MOVCX,8LEADI,ASCBUFPUSHDIPUSHCXCALLBINASCPOPCXPOPDIPUSHDICALLDISPPOPDIADDDI,10HMOVBX,BIN2MOVCX,16PUSHDIPUSHCXCALLBINASCPOPCXPOPDICALLDISPMOVAX,4C00HINT21H;转换子程序BINASCPROCREP1:ROLBX,1MOVDL,BLANDDL,01HADDDL,30H;屏蔽除最低位外的其他位MOV[DI],DLINCDILOOPREP1RETBINASCENDP;显示子程序DISPPROCREP2:MOVAH,2MOVDL,[DI]INT21HINCDILOOPREP2MOVDL,0AH;设置显示后的光标位置MOVAH,2INT21HMOVDL,0DHMOVAH,2INT21HRETDISPENDPMAINENDPCSEGENDSENDMAIN;setentrypoint19例:将两个给定的二进制数转换成为二进制数的ASCII码形式并加以显示(6-1-2.asm)方法二:用堆栈传递参数20方法二之主程序段MOVAH,BIN1;要转换的数进栈PUSHAXLEADI,ASCBUF;地址指针PUSHDIMOVAX,8;长度PUSHAXCALLBINASC;调用转换子程序MOVAX,BIN2PUSHAXADDDI,10HPUSHDIMOVAX,16PUSHAXCALLBINASC21;转换并显示子程序BINASCPROCPUSHDIPUSHAXPUSHBXPUSHCXPUSHDXPUSHBPMOVBP,SPMOVBX,[BP+18]MOVDI,[BP+16]MOVCX,[BP+14]REP1:ROLBX,1MOVDL,BLANDDL,01H;屏蔽除最低位外的其他位ADDDL,30HMOV[DI],DLMOVAH,6INT21HINCDILOOPREP1MOVAH,6MOVDL,0AHINT21HMOVAH,6MOVDL,0DHINT21HPOPBPPOPDXPOPCXPOPBXPOPAXPOPDIRET6BINASCENDP22BP=SPBX地址IP长度进入子程序时的SPAXDIBIN1CXDXBPBP+14BP+16BP+18方法二之堆栈23§6.2嵌套与递归子程序嵌套:子程序调用其他子程序,嵌套层数取决于堆栈的大小32K(基本不受限制)递归:子程序调用自己,该情况要合理设置出口参数,否则会造成程序死锁24§6.3子程序举例25例6.3十进制到十六进制数的转换(从键盘取得一个十进制数,然后把该数以十六进制的形式在屏幕上显示出来)26例6.3十进制到十六进制数的转换(6-3-1.DOC)转换方法:‘1234’((((0*10+1)*10)+2)*10+3)*10+4从最高位开始:累加和*10+本位的权值十六进制数显示的实现BHH4BHL4BLH4BLL44BHH4BHL4BLH4BLL4BHH4AL从最高位开始27;例6-3,十进制到十六进制数的转换SSEGSEGMENTPARASTACK'STACK'DW100HDUP(0)SSEGENDSDSEGSEGMENTPARA'DATA'DSEGENDSCSEGSEGMENTPARA'CODE’ASSUMECS:CSEG,DS:DSEG,SS:SSEGMAINPROCFARMOVAX,DSEG;MAKENECCESSARYINITALIZALITIONMOVDS,AXREPEAT:CALLDECIBINCALLCRLFCALLBINIHEXCALLCRLFJMPREPEATMOVAH,0AHINT21HMOVAX,4C00H;RETURNDOSINT21HMAINENDP28;从键盘获得十进制数并将其转换成十六进制数置于BX中DECIBINPROCMOVBX,0NEWCHAR:MOVAH,1INT21HSUBAL,30HJLEXIT;非十进制数则退出CMPAL,9JGEXITCBWXCHGAX,BX;将原有的数*10后加新输入的数MOVCX,10MULCXXCHGAX,BXADDBX,AXJMPNEWCHAREXIT:RETDECIBINENDP29;将BX中的十六进制数转换成相应的ASCII码显示在屏幕上BINIHEXPROCMOVCH,4;共四位十六进制数ROTATE:MOVCL,4ROLBX,CLMOVAL,BL;从最高位开始,将其移位至BX,AL的低4位ANDAL,0FHADDAL,30HCMPAL,3AHJLPRINTITADDAL,7;如为A-F的处理PRINTIT:MOVDL,ALMOVAH,2INT21HDECCHJNZROTATERETBINIHEXENDPCRLFPROCMOVDL,0AHMOVAH,2INT21HMOVDL,0DHMOVAH,2INT21HRETCRLFENDPCSEGENDSENDMAIN;SETENTRYPOINT30例6.8把以ASCII码形式表示的十进制数转换成二进制数(6-8-2.asm,6-8-1.asm增强型编程)程序限制:转换后的二进制数不超过16位转换方法:‘12345’5*1=55*01H=5H4*10=404*0AH=28H3*100=3003*64H=12CH2*1000=20002*3E8H=7D0H1*10000=100001*2710H=2710H求和=12345求和=3039H从最低位开始31增强功能的过程定义伪操作格式:PROCNAMEPROC[ATTRIBUTESFIELD][USESREGISTERLIST][,PARAMETERFIELD]……PROCNAMEENDPATTRIBUTESFIELD:DISTANCELANGUAGETYPEVISIBILITYPROLOGUE32增强功能的过程定义伪操作33例6.8.MODELSMALL.STACK64.DATAASCVALDB'12345'BINVALDW?.CODEMAINPROCFARMOVAX,@DATAMOVDS,AXLEABX,ASCVALPUSHBXLEABX,BINVALPUSHBXCALLCONVASCBINMOVBX,BINVALCALLBINIHEXMOVAX,4C00HINT21HMAINENDP34CONVASCBINPROCPASCALUSESAXBXCXSIDI,PAR1:WORD,PAR2:WORDLOCALASCLEN:WORD,MULFACT:WORDMOVBX,10MOVSI,PAR1MOVDI,PAR2SUBDI,SIMOVASCLEN,DIMOVCX,DIADDSI,CXDECSIMOVMULFACT,1MOVDI,PAR2MOVWORDPTR[DI],0NEXT:MOVAL,[SI]ANDAX,000FHMULMULFACTADD[DI],AXMOVAX,MULFACTMULBXMOVMULFACT,AXDECSILOOPNEXTRETCONVASCBINENDP35BINIHEXPROCMOVCH,4ROTATE:MOVCL,4ROLBX,CLMOVAL,BLANDAL,0FHADDAL,30HCMPAL,3AHJLPRINTITADDAL,7PRINTIT:MOVDL,ALMOVAH,2INT21HDECCHJNZROTATERETBINIHEXENDPENDMAIN;SETENTRYPOINT3637