当前位置:文档之家› 第六章 子程序结构

第六章 子程序结构

段间间接远调用:CALL DST 执行操作: (SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (CS) (SP) ← (SP) - 2 ( (SP)+1,(SP) ) ← (IP) (IP) ← (EA) (CS) ← (EA+2)
2.子程序返回指令RET 返回指令为子程序最后执行的指令,作用为断点出
LENTH DW
?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV DS,AX
LEA SI,STRG
;SI为字符串首地址,作入口参数
CALL SCONT
;调用子程序
MOV LENTH,BX
;保存结果
MOV AH,4CH
INT 21H
第六章 子程序结构
§6.1 子程序的设计方法 §6.2 嵌套与递归子程序 §6.3 子程序举例 §6.4 DOS系统功能调用
§6.1 子程序的设计方法
➢把功能相对独立的程序段单独编写和调试, 作为一个相对独立的模块供程序使用,就形 成子程序 ➢子程序可以实现源程序的模块化,可简化 源程序结构,可以提高编程效率
SCONT NEXT:
OVER: SCONT CODE
PROC XOR CMP JZ INC INC JMP
RET ENDP ENDS END
NEAR BX,BX BYTE PTR [SI],-1 OVER BX SI NEXT
START
;BX寄存器用于统计结果 ;是否结束标志 ;是则转OVER ;统计 ;修改地址指针
分析:本题子程序的功能是统计字符串长度,只需要将被 统计字符串的首地址作为入口参数传递给子程序即可。统计的 结果放在某个寄存器如BX返回即可。程序如下:
地址 …… STRG →
元素序号 ←(si) [0号元素] 1号元素 2号元素
…… -1
…… n号元素
……
字符偏移量:SI 字符个数:BX
1、初始化: (1)、让si指向首字符 2、统计字符个数: (1)、初始化BX: (BX) ←0 ;用BX存储字符个数 (2)、判断字符是否已经统计完,判断:[SI]=-1?
三、子程序的调用与返回
如果过程的属 性是far属性, 则对它的调用 和返回也是far 属性的;如果
过程的属性是 near属性,则 对它的调用和 返回也是near 属性的。
主程序
CALL 子程序名
子程序
RET
回到CALL指令后的 指令处——返回地址
code segment assume cs:code
例:带立即数返回
code main
main
segment proc far …… push ax push bx push cx call sub …… ret endp
sub
sub code
proc near
…… ret 6 endp ends
(SP) (SP)
(IP) (cx) (bx) (ax)
一、子程序指令 二、子程序的调用与返回 三、现场的保护与恢复 四、子程序参数的传递
一、过程定义伪操作
使用格式: 过程名 PROC
属性
可以是:near或far
过程代码
过程名 ENDP
属性的确定:
NEAR属性(段内近调用)的过程只 能被相同代码段的其他程序调用FAR 属性(段间远调用)的过程可以被相
同或不同代码段的程序调用
assume cs:procedure input proc far
mov ah,1 int 21h ret input endp output proc far mov dl,al mov ah,2 int 21h ret output endp procedure ends end a
三、子程序的调用与返回
A、判断:输入字符<‘A’? a.是:转2(3); b.否: 判断:输入字符>‘Z’? 是:转2(3); 否:输入字符ASCLL码+20H;
(3) 、把字符存储到si所指向的单元中:[si] ←字符; (4)、修改si,让si指向下一个存储单元:(si) ← (si) +1; (5)、转2(1); 4、结束 。
code ends end a
过程定义也可以嵌套,一个过程定义中可以包括多个过程定义。
Main proc far ;调用程序 …… call subr1 …… ret subr1 proc near ;过程subr1
…… ret subr1 endp main endp
调用程序和过程不在同一个代码段中
从子程序返回主程序,(SP+i16)用以释放参数所占的堆栈单元。 段内带立即数近返回:RET EXP段间远返回:RET 执行操作: (IP) ← ( (SP)+1,(SP) )
(SP) ← (SP) + 2 (CS) ← ( (SP)+1,(SP) ) (SP) ← (SP) + 2
段间带立即数远返回:RET EXP
堆栈段
调用程序和过程在同一个代码段中
Main proc far
…… call subr1
…… ret main endp
…… subr1 proc near
…… ret subr1 endp
;过程subr1
由于调用程序MAIN和子程序SUBR1是在 同一代码段中的,所以SUBR1定义为NEAR属 性。这样,MAIN中对SUBR1的调用和SUBR1 中的RET就都是NEAR属性的。但是一般说来, 主过程MAIN应定义为FAR属性,这是由于我们 把程序的主过程看作DOS调用的一个子过程, 因而DOS对MAIN的调用以及MAIN中的RET就 是FAR属性的
子程序的正确调用和正确返回可以保证过程的正确执行,当主程序(调用程 序)需要执行这个功能时,采用CALL调用指令转移到该子程序的 起始处执行;当运行完子程序功能后,采用RET返回指令回到主程 序继续执行
为保证其正确性,除PROC的属性要正确选择外,应该注意子程序运行期间的堆 栈状态。
由于CALL时已使返回地址入栈,所以RET时应该使返回地址出栈。如果子程 序中不能正确使用堆栈而造成执行RET前SP并未指向进入子程序时的返回地址, 则必然会导致运行出错。
①、是:结束循环,转3; ② 、否:
a、 字符个数加1 :(BX) ← (BX) +1;
b 、修改si以便让其指向下一个字符: (SI) ←(SI)+1 ;
c、转2(2); 3、把字符个数存入LENTH中: LENTH ← (BX) 。
DATA SEGMENT
STRG DB ‘HFEUWINFD4632*%587fdjljowjo#$4’,-1
code ends end a
三、子程序的调用与返回
—书写形式(同一代码段)
三、子程序的调 用与返回
—书写形式 (不同代码段)
段内调用
供段内调用的子程序必须被定义为NEAR类型,并与主程序位于 同一个代码段中。子程序的位置通常在主程序的所有可执行指令 之前或之后,不能放在主程序的可执行指令序列内部,否则会破 坏主程序结构。 【例5.1 】在以STRG为首地址的缓冲区中存放着一个字符串, 以-1作为结束标志,编程统计字符串长度,并将结果存入 LENTH单元。要求统计字符串用子程序完成。
段内间接近调用:CALL DST 执行操作: (SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (IP) (IP) ← (EA)
段间直接远调用:CALL DST 执行操作: (SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (CS) (SP) ← (SP) - 2 ( (SP)+1,(SP) ) ← (IP) (IP) ← 偏移地址 (CS) ← 段地址
段间调用
供段间调用的子程序必须被定义为FAR类型,并与主程序位 于不同的代码段中,也可分属于不同的模块。
【例5.2 】从键盘上输入一个长度小于100的字符串,存入以 BUFF为首地址的缓冲区,其中如有大写字母,要求用子程序转 换为小写字母,字符串以回车键作为结束。
分析:本例中子程序以远程子程序的方式书写,它单独占 用一个代码段。子程序的功能是将大写字母转换为小写字母, 方法是大写字母的ASCII码加上20H。程序如下:
地址 BU[第0个字符]
第1个元素 第2个元素
……
…… 第99个元素
……
字符偏移量:SI
1、初始化: (1)、让si指向首字符 2、大写字符转小写字符: (1)、输入一个字符; (2)、判断刚才的输入是否为回车:输入字符=0DH?
①、是:结束,转4; ② 、否:
转换:判断所输入字符是否为大写字符:
Segx segment ……
subt proc far …… ret
subt endp ……
SUBT为一过程,它在两处被调用,一处 是与它在同一段的SEGX段内,另一处是 在另一段SEGY段内。为此,SUBT必须具 有FAR属性以适应SEGY段调用的需要。 SUBT既然有FAR属性,则不论在SEGX段 或SEGY段,对SUBT的调用就都具有FAR 属性。
call subt ;调用程序和过程在同一个代码段中
……
Segx ends
Segy segment
……
call far ptr subt ;调用程序和过程不在同一个代码段中
……
Segy ends
code segment assume cs:code
a: call far ptr input call far ptr output mov ax,4c00h int 21h code ends procedure segment
相关主题