1、汇编语言程序设计,第 8 章 子程序设计,教案,第 8 章 子程序设计,8.1 子程序定义 8.2 子程序设计 8.3* 子程序的嵌套和递归 8.4 子程序应用例,子程序定义,子程序(过程)是具有一定功能的一组指令集合,可以在需要时被一次或多次调用。 调用子程序的程序,称为主程序;被调用的程序,称为子程序(过程)。 8086/8088子程序(过程)结构定义的伪指令 :定义子程序伪指令 PROC结束子程序伪指令 ENDP 子程序调用指令 CALL 子程序返回指令 RET,子程序(过程)定义伪指令,过程定义伪指令 PROC格式: PROC NEAR/FAR (过程的类型:NEAR 段内过程,FAR
2、 段间过程 。)过程结束伪指令ENDP格式: ENDP(PROC语句与对应的ENDP语句的过程名必须一致。),子程序调用指令,子程序调用指令CALL 格式: 直接调用: CALL 段内(近)直接调用: CALL NEAR PTR 段间(远)直接调用: CALL FAR PTR 段内(近)间接调用: CALL WORD PTR src 段间(远)间接调用: CALL DWORD PTR dsrc 操作:(1) 先把返回地址压入堆栈保存:段内调用把IP压入堆栈;段间调用把CS和IP压入堆栈。(2) 再转向被调过程:段内调用只设置IP,段间调用设置CS和IP。,子程序返回指令RET 格式: 返回:
3、RET 返回并清栈:RET n ;n 是偶数个字节数 操作:如果是段内过程,弹出IP;如果是段间过程,弹出IP和CS。如果是“RET n” ,除弹出返回地址外,(SP)+ n SP 。 注意:子程序结束必须执行到RET指令。当执行到RET指令时,SP一定要指向保存的返回地址,保证能正确返回。,子程序返回指令,子程序的结构形式,子程序(过程)结构必须在代码段结构内。SEGMENTCALL ;子程序调用PROC NEAR/FAR ;子程序定义;子程序体RET ;子程序返回ENDP ;子程序定义结束ENDS,子程序定义和调用示例,DATA SEGMENT DATA ENDS CODE SEGMENT
4、ASSUME CS:CODE,DS:DATA MAIN:CALL SUBACALL SUBB CALL FAR PTR SUBACALL NEAR PTR SUBB MOV AX, 4C00HINT 21H,SUBA PROC RET SUBA ENDP SUBB PROC FARRET SUBB ENDP CODE ENDSEND MAIN,子程序设计要点,子程序(过程)必须是具有一定功能的指令集合。 子程序(过程)结构必须被正确定义。 必须对子程序的设计给以文字说明。说明的内容:1. 子程序名;2. 子程序功能;3. 入/出口参数及传送方式;4. 子程序使用的寄存器和内存单元;5. 应用示
5、例。,子程序设计例,; P151152, 【例8.2】 计算Cm =m!/(n!*(m-n)!)的值。,;计算 N! 子程序sub1 : sub1 procmov ax, 1 next: mul cxloop nextret sub1 endp,mov cx, msub cx, ncall sub1 ; (m-n)! xchg bx, axmov dx, 0div bx ; m!/n!/(m-n)!mov ans, ax ,;数据段: m equ 4 n equ 3 ans dw ? ;主程序: mov cx, ncall sub1 ; n!mov bx, axmov cx, mcall su
6、b1 ; m!mov dx, 0div bx ; m!/n!mov bx, ax,n,保存现场和恢复现场,子程序可以被一次或多次调用,必须在子程序中有保护现场和恢复现场的处理环节。 子程序一般是利用堆栈保护现场和恢复现场。 子程序保护现场和恢复现场例P155,【例8.6】: SUB1 PROC PUSH BX PUSH CX ;保护现场BX, CX POP CX ;恢复现场BX, CX POP BX RET SUB1 ENDP,子程序的参数传递,1. 寄存器传递参数 用寄存器传递子程序入/出口参数。此方法最通用,但传递参数个数有限 。 2. 存储单元传递参数 用存储单元传递子程序入/出口参数。
7、此方法使用在传递参数个数较多,并且数据是连续存放的(数据缓冲区)。 3. 堆栈传递参数表 把传递的入口参数依次压入堆栈,然后调用子程序;子程序取堆栈中的参数表使用;返回时使用RET n 指令,弹出堆栈中的入口参数表( n为入口参数表的字节数)。,寄存器传递参数,;P157158,【例8.7】 统计字节数据区中0的个数。,arrayb db 45,23,90,125, count equ $- arrayb ans dw ? ;主程序: lea si, arraybmov cx, countcall znummov ans, axMOV AX, 4C00HINT 21H,;统计零个数子程序znu
8、m : zmun procxor ax, ax next: cmp bype ptr si, 0jnz nzinc ax nz: inc siloop nextret znum endp,存储单元传递参数,;P159160,【例8.8】 统计字节数据区中0的个数。,; 增加数据定义: para1 dw ? para2 dw ? para3 dw ? ;主程序: lea si, arraybmov para1, simov para2, countcall znummov ax, para3 mov ans, ax ,;统计零个数子程序znum : zmun procmov si, para1m
9、ov cx, para2 xor ax, ax next: cmp bype ptr si, 0jnz nzinc ax nz: inc siloop nextmov para3, axret znum endp,堆栈传递参数,;P160161,【例8.9】 统计字节数据区中0的个数。,arrayb db 45,23,90,125, count equ $- arrayb ans dw ? ;主程序: lea si, arraybmov cx, countpush sipush cxcall znumpop axmov ans, ax ,;统计零个数子程序znum : zmun procmov
10、 bp, spmov si, bp+4mov cx, bp+2 xor ax, ax next: cmp bype ptr si, 0jnz nzinc ax nz: inc siloop nextmov bp+4, axret 2 znum endp,子程序的嵌套调用,子程序的嵌套调用是指在被调子程序中又调用了其他子程序。嵌套可以达到多层。,子程序的递归调用,子程序的递归调用是指在被调子程序中直接或间接的调用了自身。,子程序递归例,;P167,【例8.11】 递归计算N! 。;数据段:N DW ? ;N 8 ANS DW ?;主程序段: MOV AX, NCALL FACTMOV ANS,
11、AX,;递归子程序fact : fact procpush dxmov dx, axcmp ax, 0jz frdec ax call fact ; (n-1)!mul dxpop dxretfr: mov ax,1 ; 1!pop dxret fact endp,;求一个无符号字变量的10#(或2#,或16# )数位之和。 ;内存数据: N dw ? S dw ? ;主程序段:(读一个数,存入N单元 )mov ax, n ; ax 取数nmov cx, 10 ; cx 取数制(或 mov cx, 2 )(或 mov cx, 16)call subr ;ax, cx 入口参数,bx 出口参数m
12、ov s, bx(输出位数之和 S单元的值),; 求数位之和子程序subr subr proc nearpush dx ;保护现场mov bx, 0 ;数位和初值0bxlop: cmp ax, 0 jz ok ;ax=0,结束求数位和mov dx, 0 div cx ;除以10/2/16add bx, dxjmp lopok: pop dx ;恢复现场ret subr endp,子程序应用例,习题8.3 (1),8.3(1) 从一个字符串中去除数字字符。(程序执行后,strd 存储区内容为STRING ); 数据段: strs db S12TR4IN63G$ ; 存放源字符串 count eq
13、u $-strs strd db count dup (?),; 主程序段: lea si, strslea di, strdcld next: lodsbcmp al, $jz exitcall jugjnc nextstosbjmp next exit: mov ax, 4c00hint 21h,;去除09数字子程序jug: jug proccmp al, 0jb charcmp al, 9ja charclcret char: stcret jug endp,8.3(2) 计算Y=3X4+X2-4X。x db 3y dw ? mov al, x ; al=3call fx ; ax=38
14、 mov dx, ax ; dx=38 mov al, x ; al=3imul al ; al=9 call fx ; ax=278 sub ax, dx ; ax=240mov y, ax ; y=240 ,;计算(3X+4)X-1子程序jug: fx procpush dxmov dl, al ; dl=xmov al, 3imul dl ; ax=3xadd ax, 4 ; ax=3x+4 xchg ax, dx ; dx=3x+4, al=x cbw ; ax=ximul dx ; ax=(3x+4)xdec ax ; ax=(3x+4)x-1pop dxret fx endp,习题
15、8.3 (2),8.4 将一个字节2#数字转换成ASCII码数符。 ; 堆栈传递3个参数: 字节数,存放ASCII码地址,位数n 。,bin db 11100011B ;一个字节数(0E3H) ascb db 8 dup (?) ;存放8个ASCII码值(31H/30H) ;主程序:mov ah, bin ;取bin字节数push ax ;压入堆栈(1)lea di, ascb ;取ascb偏移址push di ;压入堆栈(2)mov ax, 8 ;取位数8push ax ;压入堆栈(3)call btoa ;调用btoa子程序,习题8.4,;转换成ASCII码子程序btoa: btoa proc ;保护现场寄存器di, cx, dxmov bp, spmov cx, bp+8 ;取位数8mov di, bp+10 ;取ascb地址mov dx, bp+12 ;取bin字节数 next: rol dx, 1mov al, dland al, 1add al, 30h ;转换成ASCII码值mov di, al ;存放到ascb数据区inc diloop next ;恢复现场寄存器di, cx, dxret 6 ;返回,弹掉3个入口参数 btoa endp,