《汇编课件第5章子程序设计.ppt》由会员分享,可在线阅读,更多相关《汇编课件第5章子程序设计.ppt(29页珍藏版)》请在三一办公上搜索。
1、2023/10/15,1,第5章 子程序设计,2023/10/15,2,子程序设计,子程序的定义格式子程序与调用程序子程序与主程序的参数传递子程序中寄存器的保护与恢复子程序的嵌套与递归,2023/10/15,3,子程序的定义格式,用伪指令PROC定义过程,格式:过程名 PROC 属性 RET过程名 ENDP,过程名为标识符,是子程序入口的符号地址,属性是指NEAR 或 FAR 类型。,2023/10/15,4,子程序的定义格式,子程序的编写原则能反复使用、提供不同主程序使用采用较好的算法实现,节省内存、提高效率建立相关文档,满足程序使用和维护的需要说明文档中应包括:子程序的名称、功能、入口和出
2、口参数、工作寄存器、工作单元以及创建日期和修改日期等,2023/10/15,5,子程序的定义格式,过程定义举例找出以MSG0为首地址,以#作为结束的字数据区中的最小值。,MSG0DW 123,1ABH,9BCDH,0A99H,10,1234H,1A1BH,#,2023/10/15,6,子程序与调用程序,段内调用供段内调用的子程序必须被定义为NEAR类型,且与主程序位于同一个代码段内。子程序的位置通常在主程序的所有可执行指令之前或之后。不能放在可执行的指令序列内部。,在以 STR 为首地址的缓冲区中存放着一个字符串,以1 作为结束标志,编程统计字符串的长度。,2023/10/15,7,子程序与调
3、用程序,段间调用子程序必须被定义为FAR类型,并与主程序位于不同的代码段中。段间调用子程序举例从键盘上从一个长度小于100的字符串,存入以BUF为首地址的缓冲区。其中如有大写字母则转换成对应的小写字母,字符串以回车键作为结束。子程序实现大写字母的判断,并转换成小写字母,方法是大写字母的 ASCII 码加上 20H 即可,2023/10/15,8,子程序与调用程序,定义子程序CHGE实现字符转换,CODE SEGMENTASSUME CS:CODECHGE PROC FAR CMP AL,A;输入字符在AL中 JB OVER;不是大写字母 CMP AL,Z JA OVER;不是大写字母 ADD
4、AL,20hOVER:RET;返回主程序chge endpcode2 ends,2023/10/15,9,子程序与调用程序,字符串的输入利用BIOS功能调用:AH=00MOV AH,0 INT 16H输入结束的判断CMP AL,0DH,next:mov ah,0int 16hcmp al,0dhjz donecall far ptr chgemov si,alinc sijmp nextdone:mov ax,4c00hint 21h,data segmentbuff db 100 dup(?),$data endscode2 segmentassume cs:code2chge proc f
5、ar cmp al,A jb over cmp al,Z ja over sub al,20hover:retchge endpcode2 ends,code1 segment assume cs:code1,ds:datastart:mov ax,datamov ds,axlea si,buffnext:mov ah,0int 16h;输入字符cmp al,0dhjz donecall far ptr chgemov si,alinc sijmp nextdone:mov ax,4c00hint 21hcode1 endsend start,2023/10/15,11,子程序与调用程序,子程
6、序调用利用调用(CALL)指令和返回(RET)指令实现对子程序的正确调用和返回。CALL指令执行时压入堆栈的地址即是执行RET指令时供子程序返回主程序的地址。段内调用时主调程序和子程序在同一个代码段内CALL指令和RET指令的属性依赖于定义子程序时设置的属性。,2023/10/15,12,子程序与主程序间的参数传递,利用寄存器传递参数最常用的参数传递方式,最为快速直观。由于寄存器的数量有限,故只适于传递少量数目的参数。方法是主程序将子程序的入口参数放在指定的寄存器中,然后调用子程序对指定寄存器中的数据进行处理。,2023/10/15,13,利用寄存器传递参数,从DAT数据区中取数判断正负,并输
7、出相应符号:,DATA SEGMENTDAT DW 9234HDECIML DB 5 DUP(?),0DH,0AH,$DATA ENDS,2023/10/15,14,利用寄存器传递参数,从DAT字数据区中取数,转换成5位十进制数对应的ASCII码:,2023/10/15,15,利用寄存器传递参数,例子现有一DAT为首地址的字数组共有10个元素,编程按5位十进制数形式显示该10个元素,并注明正负号。要求比较正负和十进制转换分别用子程序实现,2023/10/15,16,利用寄存器传递参数,子程序中寄存器的保护与恢复如果子程序中需要使用的寄存器在主程序调用该子程序前已被使用时,需要在调用前对寄存器的
8、值进行保护。将子程序用到一些的寄存器压入堆栈进行保护需要保护寄存器的条件其中存放着主程序调用后仍要使用的内容子程序可能要改变其中的内容,2023/10/15,17,利用寄存器传递参数,子程序中寄存器的保护与恢复原则当一个子程序是公用子程序时,通常保护和恢复子程序所用到的,除了作为出口参数的寄存器之外的所有寄存器。在子程序的开始处将所有需要的寄存器入栈,返回主程序前再以相反的顺序出栈。,2023/10/15,18,子程序与主程序间的参数传递,利用存储单元传递参数适用于主程序向子程序传递的参数较多的场合,使用约定的存储单元传递参数。方法是主程序将要传递给子程序的数据存入存储单元,而在子程序调用时将
9、数据的首地址告诉子程序即可。用存储单元传递参数举例在以MSG为首地址的存储区分别存有一批数据,且以#作为结束标志,编程利用子程序调用实现将其中的最小值并存储在RSLT单元中。,2023/10/15,19,利用存储单元传递参数,DATA SEGMENT RSLT DW?MSG0 DW 123,1ABH,9BCDH,0A99H,10,1234H,1A1BH,#DATA ENDS,数据段定义:,FDMIN PROC LP:CMP WORD PTR MSG0SI,#;取操作数与#比较JZ RETURNCMP AX,SI;将操作数与AX比较JLE NEXT;AX中的值小则修改地址指针准备;与下一个数据比
10、较MOV AX,SI;AX中保持最小值NEXT:ADD SI,2;修改地址指针指向下一个字型数据JMP LPRETURN:RETFDMINENDP,DATA SEGMENT RSLT DW?MSG0 DW 123,1ABH,9BCDH,0A99H,10,1234H,1A1BH,#DATA ENDS,子程序定义:,主程序调用:,START:MOV AX,DATA MOV DS,AX MOV AX,MSG0;取第一个操作数送AX MOVSI,2;设置地址指针值 CALLFDMIN;调用子程序FDMIN MOV RSLT,AX;保存结果 MOV AX,4C00H INT 21H,DATA SEGME
11、NT RSLT DW?MSG0 DW 123,1ABH,9BCDH,0A99H,10,1234H,1A1BH,#DATA ENDS,2023/10/15,22,递归子程序设计,递归子程序子程序直接或间接地调用自身时称为递归调用。含有递归调用的子程序称为递归调用子程序。递归调用必须采用寄存器或堆栈传递参数,递归深度受到堆栈空间的限制。递归程序必须有一个退出递归的测试语句,即递归是有条件的。,2023/10/15,23,递归子程序设计,递归子程序设计编程完成求N!,主程序设计:,START:MOV AX,DATA MOV DS,AX MOV AH,0 MOV AL,NUM;取字节型数据:5 CAL
12、L FACT;调用子程序 MOVRSLT,DX;存储字型结果 MOV AH,4CH INT 21H,2023/10/15,24,递归子程序设计,子程序设计,FACTPROCNEARCMPAX,0JNZNEXTMOV DL,1RETNEXT:PUSHAXDEC ALCALLFACTPOPAXMUL DLMOV DX,AXRETFACTENDP,5 4 3 2 1,5 4 3 2 1:,5!=54!=5(43!)=5(4(32!)=5(4(3(2 1!),需要保存阶乘的每个因子,入口参数 AL出口参数 DX,2023/10/15,25,FACTPROCNEARCMPAX,0JNZNEXTMOV D
13、L,1RETNEXT:PUSHAXDEC ALCALLFACTPOPAXMUL DLMOV DX,AXRETFACTENDP,FACTPROCNEARCMPAX,0JNZNEXTMOV DL,1RETNEXT:PUSHAXDEC ALCALLFACTPOPAXMUL DLMOV DX,AXRETFACTENDP,FACTPROCNEARCMPAX,1JNZNEXTMOV DL,1RETNEXT:PUSHAXDEC ALCALLFACTPOPAXMUL DLMOV DX,AXRETFACTENDP,以 3!为例的递归过程,入口参数 AL出口参数 DX,FACTPROCNEARCMPAX,0JNZ
14、NEXTMOV DL,1;返回1!RETNEXT:PUSHAXDEC ALCALLFACTPOPAXMUL DLMOV DX,AXRETFACTENDPCODE ENDSEND START,DATA SEGMENTNUMDB 5RSLTDW?DATA ENDSSSEG SEGMENT STACK STACKDB100 DUP(?)SSEG ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA,SS:SSEGSTART:MOV AX,DATAMOV DS,AXMOV AH,0MOV AL,NUM;取操作数CALL FACT;调用子程序MOVRSLT,DX;存储结果MOV
15、AH,4CHINT 21H,2023/10/15,27,子程序与主程序间的参数传递,利用堆栈传递参数在主程序中将需要传递的数据压栈,然后调用子程序,在子程序中通过出栈操作读取数据。,PUSHPARA1PUSHPARA2.PUSHPARANCALLSUBPRG,2023/10/15,28,利用堆栈传递参数,子程序中读取入口参数的方法,SUBPRGPROC NEARPUSH BPMOV BP,SPPUSH REG1PUSH REG2.RETSUBPRGENDP,2023/10/15,29,利用堆栈传递参数,出口参数传递子程序返回前,先恢复所保护的寄存器。将堆栈中保存的返回地址出栈并保存。将出口参数压栈。将返回地址重新压栈。,SUBPRGPROC NEAR.POPREG2POP REG1POPDXPUSH PARA1PUSH DXRETSUBPRGENDP,