1、1第六章 子程序结构6.1 子程序的设计方法6.2 嵌套与递归子程序6.3 子程序举例6.4 DOS系统功能调用26.1 子程序的设计方法一、子程序指令二、子程序的调用与返回三、现场的保护与恢复四、子程序参数的传递3一、子程序指令w 子程序是完成特定功能的一段程序w 当主程序(调用程序)需要执行这个功能时,采用CALL调用指令转移到该子程序的起始处执行w 当运行完子程序功能后,采用RET返回指令回到主程序继续执行4一、子程序指令调用指令w CALL指令分成4种类型(类似JMP)nCALL label;段内调用、直接寻址nCALL r16/m16;段内调用、间接寻址nCALL far ptr l
2、abel;段间调用、直接寻址nCALL far ptr mem;段间调用、间接寻址w CALL指令需要保存返回地址:n段内调用偏移地址IP入栈 SPSP2,SS:SPIPn段间调用偏移地址IP和段地址CS入栈 SPSP2,SS:SP CS SPSP2,SS:SP IP5一、子程序指令返回指令w 根据段内和段间、有无参数,分成4种类型nRET;无参数段内返回nRET i16;有参数段内返回nRET;无参数段间返回nRET i16;有参数段间返回w 需要弹出CALL指令压入堆栈的返回地址n段内返回偏移地址IP出栈 IPSS:SP, SPSP2n段间返回偏移地址IP和段地址CS出栈 IPSS:SP,
3、SPSP2 CSSS:SP,SPSP26一、子程序指令返回指令RET的参数RET i16;有参数返回wRET指令可以带有一个立即数i16,则堆栈指针SP将增加,即SPSP+i16w这个特点使得程序可以方便地废除若干执行CALL指令以前入栈的参数7二、子程序的调用与返回CALL label主程序RET子程序回到CALL指令后的指令处返回地址8二、子程序的调用与返回书写形式(同一代码段内)9二、子程序的调用与返回书写形式(不同代码段)10三、现场的保护与恢复w 现场:主程序转向子程序之前,其所使用的一些资源的状态(如标志位、R/M等)w 子程序与主程序分别编制,通常会导致使用的资源发生冲突而影响主
4、程序在调用子程序之后的正确执行w 方法:利用堆栈n在主程序中进行n在子程序中进行11三、现场的保护与恢复在主程序中进行PUSH BXPUSH AXCALL SUB1POP AXPOP BX注意: 进栈/出栈的顺序保护与恢复的对象:主程序用到的存有数据、中间结果且在CALL指令后还要用到的R/M12三、现场的保护与恢复在子程序中进行SUB1 PROCPUSH BXPUSH AXPOP AXPOP BXRETSUB1 ENDP注意: 进栈/出栈的顺序保护与恢复的对象:子程序用到的R/M13四、子程序参数的传递w 入口参数(输入参数):主程序提供给子程序w 出口参数(输出参数):子程序返回给主程序w
5、 参数的形式: 数据本身(传值) 数据的地址(传址)w 传递的方法: 寄存器 变量 堆栈14例:将两个给定的二进制数转换成为二进制数的ASCII 码形式并加以显示w 对两个数进行转换、显示的工作是相同的,没有必要重复编写,以子程序的形式来完成w显示子程序需被告知:被显示内容的起始位置被显示内容的长度被转换的数及其长度存放结果的起始位置w转换子程序需被告知:15例:将两个给定的二进制数转换成为二进制数的ASCII码形式并加以显示(6-1-1.asm)w 方法一:用寄存器传递参数w显示子程序:DI:被显示内容的起始位置指针CX:被显示内容的长度BX:被转换的数CX:被转换数的长度DI:存放结果的起
6、始位置指针w转换子程序:16;转换子程序 BINASCPROC REP1:ROL BX,1MOV DL,BLAND DL,01HADD DL,30H;屏蔽除最低位外的其他位MOV DI,DLINC DILOOP REP1RET BINASCENDPBLBHDLDI17;显示子程序DISPPROCREP2:MOV AH,2MOV DL,DIINT 21HINC DILOOP REP2MOV DL,0AH;设置显示后的光标位置MOV AH,2INT 21HMOV DL,0DHMOV AH,2INT 21HRETDISP ENDP18DSEG SEGMENT PARA DATABIN1DB 35HB
7、IN2 DW 0AB48HASCBUFDB 20H DUP(?)DSEGENDSCSEG SEGMENT PARA CODEASSUME CS:CSEG, DS:DSEG,SS:SSEGMAIN PROC FARMOV AX,DSEGMOV DS,AXMOV BH,BIN1MOV CX,8LEA DI,ASCBUFPUSH DIPUSH CXCALL BINASCPOP CXPOP DIPUSH DICALL DISPPOP DIADD DI,10HMOV BX,BIN2MOV CX,16PUSH DIPUSH CXCALL BINASCPOP CXPOP DICALL DISPMOV AX,
8、4C00HINT 21H;转换子程序BINASCPROCREP1:ROL BX,1MOV DL,BLAND DL,01HADD DL,30H;屏蔽除最低位外的其他位MOV DI,DLINC DILOOP REP1RETBINASCENDP;显示子程序DISP PROCREP2:MOV AH,2MOV DL,DIINT 21HINC DILOOP REP2MOV DL,0AH;设置显示后的光标位置MOV AH,2INT 21HMOV DL,0DHMOV AH,2INT 21HRETDISP ENDPMAIN ENDPCSEG ENDSEND MAIN ;set entry point19例:将两
9、个给定的二进制数转换成为二进制数的ASCII码形式并加以显示(6-1-2.asm)w 方法二:用堆栈传递参数20方法二之主程序段MOV AH,BIN1;要转换的数进栈PUSH AXLEA DI,ASCBUF;地址指针PUSH DIMOV AX,8;长度PUSH AXCALL BINASC;调用转换子程序MOV AX,BIN2PUSH AXADD DI,10HPUSH DIMOV AX,16PUSH AXCALL BINASC21;转换并显示子程序BINASCPROCPUSH DIPUSH AXPUSH BXPUSH CXPUSH DXPUSH BPMOV BP,SPMOV BX,BP+18MO
10、V DI,BP+16MOV CX,BP+14REP1:ROL BX,1MOV DL,BLAND DL,01H ;屏蔽除最低位外的其他位ADD DL,30HMOV DI,DLMOV AH,6INT 21HINC DILOOP REP1MOV AH,6MOV DL,0AHINT 21HMOV AH,6MOV DL,0DHINT 21HPOP BPPOP DXPOP CXPOP BXPOP AXPOP DIRET 6BINASC ENDP22BP=SPBX地址IP长度进入子程序时的SPAXDIBIN1CXDXBPBP+14BP+16BP+18方法二之堆栈236.2 嵌套与递归子程序w 嵌套:子程序调
11、用其他子程序,嵌套层数取决于堆栈的大小32K(基本不受限制)w 递归:子程序调用自己,该情况要合理设置出口参数,否则会造成程序死锁246.3 子程序举例25例 6.3 十进制到十六进制数的转换(从键盘取得一个十进制数,然后把该数以十六进制的形式在屏幕上显示出来)26例 6.3 十进制到十六进制数的转换(6-3-1.DOC)w 转换方法:1234(0*10+1)*10)+2)*10+3)*10+4从最高位开始:累加和*10+本位的权值w 十六进制数显示的实现BHH4BHL4BLH4BLL44BHH4BHL4BLH4BLL4BHH4AL从最高位开始27;例6-3,十进制到十六进制数的转换SSEG
12、SEGMENT PARA STACK STACKDW 100H DUP(0) SSEG ENDS DSEG SEGMENT PARA DATADSEG ENDSCSEG SEGMENT PARA CODEASSUME CS:CSEG, DS:DSEG,SS:SSEGMAIN PROC FARMOV AX,DSEG;MAKE NECCESSARY INITALIZALITIONMOV DS,AXREPEAT: CALL DECIBINCALL CRLFCALL BINIHEXCALL CRLFJMP REPEATMOV AH,0AHINT 21HMOV AX,4C00H;RETURN DOSIN
13、T 21HMAIN ENDP28;从键盘获得十进制数并将其转换成十六进制数置于BX中DECIBIN PROCMOV BX,0NEWCHAR:MOV AH,1INT 21HSUB AL,30HJL EXIT;非十进制数则退出CMP AL,9JG EXITCBWXCHG AX,BX;将原有的数*10后加新输入的数MOV CX,10MUL CXXCHG AX,BXADD BX,AXJMP NEWCHAREXIT:RETDECIBIN ENDP29;将BX中的十六进制数转换成相应的ASCII码显示在屏幕上BINIHEX PROC MOV CH,4;共四位十六进制数ROTATE: MOV CL,4ROL
14、 BX,CLMOV AL,BL;从最高位开始,将其移位至BX,AL的低4位AND AL,0FHADD AL,30HCMP AL,3AHJL PRINTITADD AL,7;如为A-F的处理PRINTIT: MOV DL,ALMOV AH,2INT 21HDEC CHJNZ ROTATERETBINIHEX ENDPCRLFPROCMOV DL,0AHMOV AH,2INT 21HMOV DL,0DHMOV AH,2INT 21HRETCRLFENDPCSEG ENDSEND MAIN ;SET ENTRY POINT30例 6.8 把以ASCII码形式表示的十进制数转换成二进制数(6-8-2.
15、asm,6-8-1.asm增强型编程)w 程序限制:转换后的二进制数不超过16位w 转换方法:123455*1= 5 5*01H= 5H4*10 = 404*0AH= 28H3*100= 3003*64H= 12CH2*1000= 20002*3E8H= 7D0H1*10000= 100001*2710H=2710H求和= 12345求和=3039H从最低位开始31增强功能的过程定义伪操作格式:PROCNAMEPROC ATTRIBUTES FIELD USES REGISTER LIST ,PARAMETER FIELDPROCNAMEENDPATTRIBUTES FIELD :DISTAN
16、CE LANGUAGE TYPE VISIBILITYPROLOGUE32增强功能的过程定义伪操作33例6.8.MODEL SMALL.STACK 64.DATAASCVAL DB 12345BINVALDW ?.CODEMAIN PROC FARMOV AX,DATAMOV DS,AXLEA BX,ASCVALPUSH BXLEA BX,BINVALPUSH BXCALL CONVASCBINMOV BX,BINVALCALL BINIHEXMOV AX,4C00HINT 21HMAIN ENDP34CONVASCBINPROC PASCAL USES AX BX CX SI DI,PAR1
17、:WORD,PAR2:WORDLOCAL ASCLEN:WORD,MULFACT:WORDMOV BX,10MOV SI,PAR1MOV DI,PAR2SUB DI,SIMOV ASCLEN,DIMOV CX,DIADD SI,CXDEC SIMOV MULFACT,1MOV DI,PAR2MOV WORD PTR DI,0NEXT:MOV AL,SIAND AX,000FHMUL MULFACTADD DI,AXMOV AX,MULFACTMUL BXMOV MULFACT,AXDEC SILOOP NEXTRETCONVASCBINENDP35BINIHEX PROC MOV CH,4RO
18、TATE: MOV CL,4ROL BX,CLMOV AL,BLAND AL,0FHADD AL,30HCMP AL,3AHJL PRINTITADD AL,7PRINTIT: MOV DL,ALMOV AH,2INT 21HDEC CHJNZ ROTATERETBINIHEX ENDPEND MAIN ;SET ENTRY POINT3637例:6.9 十六进制到十进制数的转换 w 把从键盘输入的0-FFFF的十六进制正数转换成十进制数并在屏幕上显示出来nHexibin :键盘输入十六进制数其数值在BX中ncrlf :回车换行nBinidec:十六进制到十进制转换并显示38例6.9DISPE
19、QU 2HKEY_INEQU 1HDOSCALL EQU 21HSSEG SEGMENT PARA STACK STACKDW 100H DUP(0) SSEG ENDS CSEG SEGMENT PARA CODEASSUME CS:CSEG, SS:SSEGMAINPROC FARMOV CL,4CALL HEXIBIN;调用十六进制数输入子程序CALL CRLFCALL BINIDEC;调用十六进制到十进制转换子程序CALL CRLFJMP MAINMOV AX,4C00HINT 21HMAIN ENDP39例6.9;十六进制输入并转换为十六进制数值子程序,十六进制数值在BX中HEXIB
20、IN PROC MOV BX,0 NEWCHAR: MOV AH,KEY_ININT DOSCALLSUB AL,30HJL EXIT;非十六进制数值输入则结束输入CMP AL,10JL ADD_TOSUB AL,27HCMP AL,10HJGE EXITADD_TO:SHL BX,CL;新输入的数值(在AL的低四位上)加入到BX的低四位中MOV AH,0ADD BX,AXJMP NEWCHAREXIT:RETHEXIBIN ENDP40例6.9;十六进制到十进制转换并显示子程序;被除数是BX,除数分别是10000,1000,100,10,1,;;商是十进制;数,余数作为下次的被除数BINID
21、EC PROCMOV CX,10000DCALL DEC_DIVMOV CX,1000DCALL DEC_DIVMOV CX,100DCALL DEC_DIVMOV CX,10DCALL DEC_DIVMOV CX,1CALL DEC_DIVRETBINIDEC ENDPDEC_DIVPROCMOV AX,BXMOV DX,0DIV CXMOV BX,DXMOV DL,ALADD DL,30HMOV AH,DISPINT DOSCALLRETDEC_DIVENDP41例6.9CRLFPROCMOV DL,0AHMOV AH,DISPINT DOSCALLMOV DL,0DHMOV AH,DIS
22、PINT DOSCALLRETCRLFENDPCSEG ENDSEND MAIN42例6.10 一个简单的信息检索系统w 数据区里有10个不同的信息,编号为0-9,每个信息包括30个字符。编制程序从键盘接收0-9之间的编号,然后在屏幕上显示相应编号的信息内容。w (6-10.asm,6-10.doc)43SSEG SEGMENT PARA STACK stackDW 100H DUP(0) SSEG ENDS DSEG SEGMENT PARA DataTHIRTYDB ?MESG0DB This is message 0-MESG1DB This is message 1-MESG2DB T
23、his is message 2-MESG3DB This is message 3-MESG4DB This is message 4-MESG5DB This is message 5-MESG6DB This is message 6-MESG7DB This is message 7-MESG8DB This is message 8-MESG9DB This is message 9-LENEQU MESG1-MESG0ERRMSG DB error! invilid parameter!DSEG ENDS例例6.10:1/344CSEG SEGMENT PARA CODEASSUM
24、E CS:CSEG, DS:DSEG,SS:SSEGMAIN PROC FARMOV AX,DSEGMOV DS,AXMOV THIRTY, LENBEGIN:MOV AH,1INT 21HSUB AL,0JC ERRORCMP AL,9JA ERRORPUSH AXMOV DL,0AHCALL DISPCHARMOV DL,0DHCALL DISPCHARPOP AXMOV BX, OFFSET MESG0MUL THIRTYADD BX,AXCALL DISPJMP BEGINERROR:MOV BX,OFFSET ERRMSGCALL DISPMOV AX,4C00HINT 21H例例6
25、.10:2/345DISPPROCMOV CX,30DISP1:MOV DL,BXCALL DISPCHARINC BXLOOP DISP1MOV DL,0AHCALL DISPCHARMOV DL,0DHCALL DISPCHARRETDISPENDP DISPCHARPROCMOV AH,2INT 21HRET DISPCHARENDPMAIN ENDPCSEGENDSEND MAIN ;SET ENTRY POINT例例6.10:3/346例6.11 人名排序程序。从键盘键入最多30个人名,当所有人名都进入后,按字母上升的次序将人名排序,并在屏幕上显示已排序后的人名(6-11)47w b
26、10read:输入子程序(所占空间固定,但要将多出部分清为空格)w D10stor:将本次输入存储到表中(DI中是在表中起始地址的指针,同时计存储到表中的名字的个数)w g10sort :排序(冒泡排序)nH10 xch:交换表中相邻项的顺序 w K10disp:显示已排序的名字表 w Q10clr:清屏 w Q20curs:设置光标位置 48DSEG SEGMENT PARA DATA NAMEPARLABEL BYTE MAXLENDB 21 NAMELENDB ? NAMEFLDDB 21 DUP(?) CRLFDB 13,10,$ ENDADDRDW ?MESG1DB NAME? ,$
27、 NAMECTRDB 0 NAMETABDB 30 DUP(20 DUP( ) NAMESAVDB 20 DUP(?),13,10,$ SWAPPEDDB 0DSEG ENDSCSEG SEGMENT PARA CODEASSUME CS:CSEG, DS:DSEGMAIN PROC FARMOV AX,DSEGMOV DS,AXMOV ES,AX例例6.11:1/649CLDLEA DI,NAMETAB;表首址作为目的串的首址CALL Q10CLRCALL Q20CURS A20LOOP:CALL B10READ;调输入子程序CMP NAMELEN,0JZ A30CALL D10STOR;存
28、储JMP A20LOOPA30:CALL Q10CLRCALL Q20CURSCMP NAMECTR,1JBE A40CALL G10SORTA40:CMP NAMECTR,0JBE EXITCALL K10DISPEXIT:MOV AX,4C00HINT 21HMAIN ENDP例例6.11:2/650;名字输入子程序 B10READPROCMOV AH,9LEA DX,MESG1INT 21HMOV AH,0AHLEA DX,NAMEPARINT 21HMOV AH,9LEA DX,CRLFINT 21HMOV BH,0;缓存区的空余部分填空格MOV BL,NAMELENMOV CX,21
29、SUB CX,BXB20:MOV NAMEFLDBX,20HINC BXLOOP B20RET B10READENDP ;名字存储子程序 D10STORPROC ;名字个数计数器加1INC NAMECTRCLDLEA SI,NAMEFLDMOV CX,10REP MOVSWRET D10STORENDP例例6.11:3/651;排序子程序 G10SORTPROCSUB DI,40MOV ENDADDR,DIG20:MOV SWAPPED,0;交换标志清0LEA SI,NAMETABG30:MOV CX,20MOV DI,SIADD DI,20MOV AX,DIMOV BX,SIREPE CMP
30、SBJBE G40CALL H10XCH;调用交换顺序子程序G40:MOV SI,AXCMP SI,ENDADDRJBE G30CMP SWAPPED,0JNZ G20RET G10SORTENDP例例6.11:4/652;交换表的内容H10XCH PROCMOV CX,10LEA DI,NAMESAVMOV SI,BXREP MOVSWMOV CX,10MOV DI,BXREP MOVSWMOV CX,10LEA SI,NAMESAVREP MOVSWMOV SWAPPED,1RETH10XCH ENDP;显示已排序的名字表 K10DISPPROCLEA SI,NAMETABK20:LEA
31、DI,NAMESAVMOV CX,10REP MOVSWMOV AH,9LEA DX,NAMESAVINT 21HDEC NAMECTRJNZ K20RET K10DISPENDP例例6.11:5/653;清屏子程序Q10CLR PROCMOV AX,0600HMOV BH,61HSUB CX,CXMOV DX,184FHINT 10HRETQ10CLR ENDP;设置光标位置子程序 Q20CURSPROCMOV AH,2SUB BH,BHSUB DX,DXINT 10HRET Q20CURSENDPCSEG ENDSEND MAIN ;SET ENTRY POINT例例6.11:6/6546
32、.4 DOS系统功能调用裸机裸机汇编语言程序55系统功能调用w 21H号中断是DOS提供给用户的用于调用系统功能的中断,它有近百个功能供用户选择使用,主要包括设备管理、目录管理和文件管理三个方面的功能w ROM-BIOS也以中断服务程序的形式,向程序员提供系统的基本输入输出程序w 汇编语言程序设计需要采用系统的各种功能程序w 充分利用操作系统提供的资源是程序设计的一个重要方面,需要掌握56功能调用的格式通常按照如下4个步骤进行:w在AH寄存器中设置系统功能调用号w在指定寄存器中设置入口参数w执行指令INT 21H(或ROM-BIOS的中断向量号) 实现中断服务程序的功能调用w根据出口参数分析功
33、能调用执行情况57字符输出的功能调用w DOS功能调用INT 21Hn功能号:AH02Hn入口参数:DL字符的ASCII码n功能:在显示器当前光标位置显示给定的字符,光标右移一个字符位置。如按Ctrl-Break或Ctrl-C则退出 ;在当前显示器光标位置显示一个问号MOV AH,02H;设置功能号:AH02HMOV DL,?;提供入口参数:DL?INT 21H;DOS功能调用:显示58字符串输出的功能调用w DOS功能调用INT 21Hn功能号:AH09Hn入口参数:nDS:DX欲显示字符串在主存中的首地址n字符串应以$(24H)结束n功能:在显示器输出指定的字符串w 可以输出回车(0DH)
34、和换行(0AH)字符产生回车和换行的作用59字符串输出的功能调用显示字符串(例)STR DB Hello,Everybody !,0DH,0AH,$;在数据段定义要显示的字符串.MOV AH,09H ;设置功能号:AH09HMOV DX,OFFSET STR;提供入口参数:DX字符串的偏移地址INT 21H ;DOS功能调用:显示60字符输入的功能调用w DOS功能调用INT 21Hn功能号:AH01Hn出口参数:AL字符的ASCII码n功能:获得按键的ASCII代码值w 调用此功能时,若无键按下,则会一直等待, 直到按键后才读取该键值61字符输入的功能调用判断按键(例)GETKEY:MOV
35、AH,01H;功能号:AH01HINT 21H;功能调用CMP AL,Y;处理出口参数ALJE YESKEY;是“Y”CMP AL,NJE NOKEY;是“N”JNE GETKEY.YESKEY:.NOKEY:.62字符串输入的功能调用w DOS功能调用INT 21Hn功能号:AH0AHn入口参数:DS:DX缓冲区首地址w 执行该功能调用时,用户按键,最后用回车确认w 本调用可执行全部标准键盘编辑命令;用户按回车键结束输入,如按CtrlBreak或CtrlC则中止关键要定义好缓冲区63字符串输入的功能调用缓冲区的定义w 第1字节事先填入最多欲接收的字符个数(包括回车字符,可以是1255)w 第2字节将存放实际输入的字符个数(不包括回车符)w 第3字节开始将存放输入的字符串w 实际输入的字符数多于定义数时,多出的字符丢掉,且响铃w 接收的字符串最后一个总是回车符64字符串输入的功能调用输入字符串(例);定义缓冲区BUFDB 81 ;第1个字节填入可能输入的最大字符数DB 0;存放实际输入的字符数DB 81 DUP(0);存放输入的字符串.MOV DX,SEG BUF;伪指令SEG取得BUFFER的段地址MOV DS,DX;设置数据段DSMOV DX,OFFSET BUFMOV AH,0AHINT 21H