资源预览内容
第1页 / 共7页
第2页 / 共7页
第3页 / 共7页
第4页 / 共7页
第5页 / 共7页
第6页 / 共7页
第7页 / 共7页
亲,该文档总共7页全部预览完了,如果喜欢就下载吧!
资源描述
子程序存储在存储器中,可供一个或多个调用程序(主程序)反复调用。主程序调用子程 序时使用 CALL 指令,由子程序返回主程序时使用 RET 指令。由于调用程序和子程序可以 在同一个代码段中,也可以在不同的代码段中,因此,CALL 指令和 RET 指令也有近调用、 近返回及远调用、远返回两类格式。 CALL NEAR PTR 近调用(near call)近调用是 CALL 指令的缺省格式,可以写为“CALL rotine“。它调用同一个 代码段内的子程序(子过程) ,因此,在调用过程中不用改变 CS 的值,只需将子程序的地 址存入 IP 寄存器。CALL 指令中的调用地址可以用直接和间接两种寻址方式表示。 CALL FAR PTR 远调用(far call)远调用适用于调用程序(也称为主程序)和子程序不在同一段中的情况,所以也叫做 段间调用。和近调用指令一样,远调用指令中的寻址方式也可用直接方式和间接方式。 RET 返回指令(return)RET 指令执行的操作是把保存在堆栈中的返回地址出栈,以完成从子程序返回到调用 程序的功能。 CALL 段内直接调用 执行操作: (SP) (SP)-2,(SP) (IP)当前 (IP) (IP)当前16 位位移量(在指令的第 2、3 个字节中) CALL DESTIN 段内间接调用 执行操作: (SP) (SP)-2,(SP) (IP)当前 (IP) (EA) ; (EA)为指令寻址方式所确定的有效地址 CALL FAR PTR 段间直接调用 执行操作: (SP) (SP)-2,(SP) (CS)当前(SP) (SP)-2,(SP) (IP)当前 (IP) 偏移地址(在指令的第 2、3 个字节中)(CS) 段地址(在指令的第 4、5 个字节中) CALL WORD PTR DESTIN 段间间接调用执行操作: (SP) (SP)-2,(SP) (CS)当前(SP) (SP)-2,(SP) (IP)当前 (IP) (EA) ; (EA)为指令寻址方式所确定的有效地址(CS) (EA+2)从 CALL 指令执行的操作可以看出,第一步是把子程序返回调用程序的地址保存在堆 栈中。对段内调用,只需将 IP 的当前值,即 CALL 指令的下一条指令的地址存入 SP 所指 示的堆栈字单元中。对段间调用,保存返回地址则意味着要将 CS 和 IP 的当前值分别存入 堆栈的两个字单元中。CALL 指令的第二步操作是转子程序,即把子程序的入口地址交给 IP(段内调用)或 CS:IP(段间调用) 。对段内直接方式,调转的位移量,即子程序的入口地址和返回地址之间的差值就在机器指令的 2、3 字节中。对段间直接方式,子程序的偏移地址和段地址就在 操作码之后的两个字中。对间接方式,子程序的入口地址就从寻址方式所确定的有效地址 中获得。 RET 段内返回(近返回)执行操作:(IP) (SP),(SP) (SP)2 RET 段间返回(远返回)执行操作:(IP) (SP),(SP) (SP)2 (CS) (SP),(SP) (SP)2 RET N 带立即数返回执行操作: 返回地址出栈(操作同段内或段间返回) 修改堆栈指针:(SP) (SP)N子程序的最后一条指令必须是 RET 指令,以返回到主程序。如果是段内返回,只需把 保存在堆栈中的偏移地址出栈存入 IP 即可,如果是段间返回,则要把偏移地址和段地址都 从堆栈中取出送到 IP 和 CS 寄存器中。带立即数返回指令,除完成偏移地址出栈或偏移地址和段地址出栈的操作外,还要再 使 SP 的内容加上一个立即数 N,使堆栈指针 SP 移动到新的位置。指令中的 N 可以是一个 常数,也可以是一个表达式。带立即数返回指令适用于 C 或 PASCAL 的调用规则,这些规 则在调用过程(子程序)前先把参数压入堆栈,子程序使用这些参数后,如果在返回时丢 弃这些已无用的参数,就在 RET 指令中包含一个数字,它表示压入到堆栈中参数的字节数, 这样堆栈指针就恢复到参数入栈前的值。CALL 指令和 RET 指令都不影响条件码。例 3.43 根据下面调用程序和子程序的程序清单,画出 RET 指令执行前和执行后的堆栈 情况。假设初始的 SS:SP=A000:1000。0000 B8 001E MOV AX,300003 BB 0028 MOV BX,400006 50 PUSH AX ; push data1 into stack0007 53 PUSH BX ; push data2 into stack0008 E8 0066 CALL ADDM ; call 000B B4 02 MOV AH,2 0071 ADDM PROC NEAR ; entry point (IP)0071=000b+00660071 55 PUSH BP ; save BP 0072 8B E4 MOV BP,SP ; addressing the stack with BP0074 8B 46 04 MOV AX,BP+4 ; get data2 from stack0077 03 46 06 ADD AX,BP+6 ; add data1007A CD POP BP ; get back BP007B C2 0004 RET 4 ; return and revert SP007E ADDM ENDP图 3.12 CALL 指令和 RET 指令对堆栈的影响 如图 3.12 所示,主程序中的两条 PUSH 指令将数据 30 和 40 压入堆栈,CALL 指令执 行后,返回地址 000B 又压入堆栈,紧接着程序控制转移到子程序 ADDM。子程序中的 PUSH 指令又使 BP 的值进栈,此时 SP 指向栈顶 0FFA。MOV 指令将 0FFA 传送给 BP, 使 BP 作为寻址堆栈数据的指针。 (BP+4)指向的是 40, (BP+6)指向的是 30,取出数据 后用 POP 指令恢复了 BP 原先的值,此时,(SP)=0FFC,这是 RET 4 指令执行前的堆栈状 态。执行 RET 4 指令时,先使返回地址出栈:(IP)000B,(SP)0FFC+2=0FFD,然后, (SP)+4=0FFD+4=1000,结果使 SP 跳过了堆栈数据而回到了原始位置。6.4.4 子程序应用举例 【例】将一个给定的二进制数按位转换成相应的 ASCII 码字符串,送到指定的存储单元并 显示。如二进制数 10010011 转换成字符串为10010011。要求将转换过程写成子程序,且 子程序应具有较好的通用性,而必须能实现对 8 倍和 16 倍二进制数的转换。入口参数:DX 存放待转换的二进制数 CX 存放待转换数的位数(8 位或 16 位) DI 存放 ASCII 码首地址 出口参数:转换后的字符串存放在以 DI 作指针的字节存贮区中 程序如下: DATASEGMENT NUM8DB 93H NUM16 DW 0ABCDH ASCBUF DB 20 DUP(0) DATAENDS CODESEGMENT ASSUME DS:DATA,CS:CODE, SS:STACKSTART:MOVAX,DATA MOVDS,AX MOVDX,0 MOVDL,NUM8;转换二进制数送 DX MOVCX,8;置位数 8 LEADI,ASCBUF;字符串首址DI CALLBTASC ;调用子程序 BTASC MOVDI,BYTE PTR 0DH MOVDI+1,BYTE PTR 0AHMOVDI+2,BYTE PTR $ LEA DX,ASCBUF MOVAH,9 INT 21H MOVDX,NUM16 MOVCX,16 ;置位数 16 LEADI,ASCBUF CALLBTASCMOVDL,BYTE PTR 0DH MOVDL+1,BYTE PTR 0AH MOVDL+2,BYTE PTR ; 显示转换后的字符串 LEA DX, ASCBUF MOVAH,9 INT 21HBTASC PROC PUSHAX ;保存 AX MOVAL,0 CMPCX,8;比较 8 位数 JNE L1;直接转换 16 位数 MOVDH,DL ;8 位数转换送 DH L1:ROLDX,,1;DX 最高位移入 CF RCLAL,1;CF 移入 AL 最低位 ADDAL,30H MOVDI,AL INC DI LOOPL1 POPAX RET BTASC ENDP CODEENDS END START(1)通过寄存器传送参数)通过寄存器传送参数这是最常用的一种方式,使用方便,但参数很多时不能使用这种方法。十进制到十六进制数转换程序。程序要求从键盘取得一个十进制数,然后把该数以十六进制形式在屏幕上显示出来。采用子程序结构,用一个子程序 DECIBIN 实现从键盘取得十进制数并把它转换为二进制数;另一个子程序 BINIHEX 把此二进制数以十六进制数的形式在屏幕上显示出来。为避免屏幕上的重叠,另外用CRLF 子程序取得回车和换行的效果。整个程序结构如动画所示,在这里,各个子程序之间用 BX 寄存器来传送信息。decihex segmentassume cs:decihex; 程序的主要部分main proc far repeat: call decibin ; 调用子程序 decibincall crlf ; 调用子程序 crlfcall binihex ; 调用子程序 binihexcall crlf jmp repeat main endp ; 子程序 decibindecibin proc nearmov bx,0 newchar:mov ah,1 int 21h ; 从键盘接收单个字符 ; 非 09 之间的数退出sub al,30h jl exit cmp al,9d jg exit cbw ; al 扩展到 ax; BX 中的数乘以 10xchg ax,bx mov cx,10d mul cx xchg ax,bx ; 把 ax 加到 bx 中add bx,ax jmp newchar ; 接收下一个字符exit:ret decibin endp; 子程序 binihex binihex proc near mov ch,4 rotate: mov cl,4 rol bx,cl mov al,bl and al,0fh add al,30h cmp al,3ah jl printit add al,7h printit:mov dl,al mov ah,2 int 21h dec ch jnz rotate ret binihex endp; 子程序 crlfcrlf proc near ; 显示回车 mo
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号