当前位置:
文档之家› 第6章 子程序结构---段内定义和使用
第6章 子程序结构---段内定义和使用
第6章
子程序结构
【例6-1】 调用程序和子程序在同一代码段中。
Code segment … CALL SUBR1 … PROC RET …. NEAR ;子程序(NEAR可省略) SUBR1 ;主程序
SUBR1
Code ends
ENDP
第6章
子程序结构
由于调用程序MAIN和子程序SUBR1在同一代码段
转移到子程序,这个过程称为转子。子程序执行完了,
要把控制再返回到主程序,这个过程称为返主。主程 序与子程序之间的关系如图6.1所示。
第6章
子程序结构
主程序 1 调用子程序 2 3 调用子程序 1 调用子程序 2 3 返回 子程序
图6.1 主程序与子程序之间的关系
第6章
子程序结构
子程序具有如下4个特性: (1) 重复性。 一个子程序只占用一段存储区域,但可以多次被 调用,避免了编程人员的重复劳动,又节省程序的存 储空间。由于增加了调用、返回等指令,因此程序执
第6章
子程序结构
程序如下:
DECIHEX SEGMENT ASSUME CS: DECIHEX
MAIN
REPEAT:
PROC FAR
CALL DECIBIN CALL CRLF ;调用键入子程序 ;调用回车换行子程序
CALL BINIHEX
CALL CRLF JMP
;调用转换子程序
;调用回车换行子程序
第6章
子程序结构
第6章 子程序结构
6.1 子程序的概念 6.2 子程序结构定义与调用 6.3 子程序的参数传送 6.4 子程序的嵌套与递归 习题6
第6章
子程序结构
6.1 子程序的概念
6.1.1 子程序概念 把可以多次调用、能够完成特定操作功能的程序 段/指令集编写成独立的程序模块,该程序模块称为子 程序,又称为过程。调用这些子程序的程序称为主程 序。在主程序中,如果调用到子程序,就需要把控制
NUM数组前,先把NUM数组及N的内容全部传送到
ARY数组和COUNT单元去,PROADD运行完后,再把 SUM的结果送到TOTAL去。这显然不是一种好办法。 为解决这一类问题,下面分别介绍“通过地址表传送 参数地址”和“通过堆栈传送参数或参数地址”两种 参数传送的方法。
第6章
子程序结构
6.3.3 通过地址表传送参数地址
PROC NEAR AX CX SI SI,ARY CX,COUNT AX,AX
第6章
子程序结构
NEXT:ADD AX,[SI]
ADD SI,2 LOOP NEXT
MOVSUM,AX POP SI
POP CX
POP AX RET PROADD CODE ENDS ENDP
END
START
第6章
子程序结构
ret
endp
第6章
子程序结构
其中,子程序名为标识符,它又是子程序入口的符号地址。 它的写法与标号的写法相同。属性(Attribute)是指子程序的类型属
性,可以是NEAR或FAR。
如果所定义的子程序是NEAR属性的,那么对它的调用和返 回也一定是NEAR属性的。这样,用户只需在定义子程序时考虑 它的属性,而CALL和RET的属性可以由汇编程序来确定。子程序 属性的确定原则很简单,即: ① 如调用程序和子程序在同一个代码段中,则使用NEAR属性; ② 如调用程序和子程序不在同一个代码段中,则使用FAR属 性。
这种方法是在主程序中建立一个地址表,把要传 送给子程序的参数都存放在地址表中,然后把地址表 的首地址通过寄存器BX传送到子程序中去。子程序通 过地址表取得所需参数,并把结果存入指定的存储单 元中去。这样做的结果,对于上述程序中要累加NUM 数组的内容时,只需在程序中增加下述指令,再调用 PROADD,就能在TOTAL中得到NUM的累加和。
子程序结构
CMP
JG EXIT CBW
AL,9
;数大于9?
;是,退出 ;否,调整成16位
XCHG AX,BX MOV CX,10
MUL
CX
;乘10
XCHG AX,BX ADD JMP BX,AX NEWCHAR ;取下一个字符
第6章
子程序结构
EXIT: DECIBIN
RET ENDP
BINIHEX
子程序的类型与call指令执行、返回!
第6章
子程序结构
6.2.3 现场保护与现场恢复 主程序和子程序通常是分别编制的,所以它们所 使用的寄存器往往会发生冲突。如果主程序在调用子 程序之前的某个寄存器内容在从子程序返回后还有用, 而子程序又恰好使用了同一个寄存器,这就破坏了该
寄存器的原有内容,因而造成程序运行错误,这是不
AH,2
21H DL,0AH ;执行换行
MOV
INT RET
AH,2
21H
CRLF
DECIHEX
ENDP
ENDS END MAIN
第6章
子程序结构
6.3.2 直接参数传递 若子程序和调用程序在同一源文件(同一程序模块)中, 则子程序可直接访问模块中的变量,进行参数传递。 【例6-5】 主程序MAIN和子程序PROADD在同一源 文件中,要求用子程序PROADD累加数组中的所有元素,
间传送参数的话,则这种寄存器就不一定需要保护,特
别是用来向主程序回送结果的寄存器,就更不应该因保 存和恢复寄存器而破坏了应该向主程序传送的信息。
第6章
子程序结构
6.3 子程序的参数传送
主程序在调用子程序时,经常需要传送一些参数 给子程序,子程序运行完后也经常要回送一些信息给 主程序。这种调用程序和被调用程序之间的信息传送 称为主—子程序参数传送(或称变量传送和过程通信)。 以下介绍参数传送的常用方式。
SEGY
SEGMENT CALL SUBT
SEGY
ENDS
第6章
子程序结构
6.2.2 子程序的调用和返回 子程序的调用: call 子程序名
子程序的返回: 在子程序中最后一条指令使用 ret 子程序的正确执行是由子程序的正确调用和正确 返回保证的。80x86的CALL和RET指令完成的就是调
用和返回的功能。
PUSH
PUSH PUSH PUSH <子程序体>
AX
BX CX DX
;现场保护
第6章
子程序结构
POPDX POPCX POPBX POPAX RET SUBT ENDP
;现场恢复
第6章
子程序结构
在子程序设计时,应仔细考虑哪些寄存器必须保护,
哪些不必保护。一般说来,子程序中用到的寄存器是应 该保护的。但是,如果使用寄存器在主程序和子程序之
中,所以SUBR1定义为NEAR属性。这样,MAIN中对 SUBR1的调用和SUBR1中的RET就都是NEAR属性的。
第6章
子程序结构
【例6-2】 调用程序和子程序不在同一个代码段内。 SEGX SUBT SEGMENT (详见段间调用) PROC FAR
……………
RET SUBT SEGX ENDS ENDP
允许的。为避免这种错误的发生,在一进入子程序后, 就应该把子程序所需要使用的寄存器内容保存在堆栈
中,此过程称作现场保护。在退出子程序前把寄存器
内容恢复原状,此过程称作现场恢复。现场保护与现 场恢复分别使用压栈和弹出指令实现。
第6章
子程序结构
【例6-3】 保护现场与恢复现场示例。 SUBT PROC
把BX寄存器中的数用十六进制形式显示出来。也就是
说,BX寄存器用来在子程序间传递要转换的数。
第6章
子程序结构
开始 从键盘取得十进制 数,保存在BX中 显示回车和换行 用十进制形式显 示BX中的数
调用DECIBIN
调用CRLF
调用BINIHEX
调用CRLF
结束
பைடு நூலகம்
图6.2 十进制数到十六进制数转换的程序结构
第6章
子程序结构
(3) 可浮动性。 所谓可浮动性,就是说子程序可以存放在存储区
的任何地址处。假如子程序只能存放在固定的地址处,
则在编写主程序时要特别注意存储单元的分配,不要 使主程序占用了子程序的存储单元而破坏掉子程序,
这样就会给编程人员带来很大麻烦,而且在装配主程
序和子程序时往往造成存储空间的冲突或浪费。
第6章
子程序结构
MOV TABLE,OFFSET NUM
MOV TABLE+2,OFFSET N MOV TABLE+4,OFFSET TOTAL MOV BX,OFFSET TABLE CALL PROADD
第6章
子程序结构
6.1.2 子程序分类
按子程序的定义和调用分为:
一、子程序段内调用
二、子程序段间调用
第6章
子程序结构
6.2 子程序段内调用结构定义与操作
6.2.1子程序定义
该伪操作用在子程序的前后,使整个子程序形成清
晰的、具有特定功能的代码块。其格式为:
子程序名
子程序名
… …
proc …….
ATTRIBUTE(NEAR、FAR)
ASSUME CS:CODE,DS:DATA
第6章
子程序结构
START: SUB PUSH MOV MOV CALL RET
PUSH DS AX,AX AX AX,DATA DS,AX NEAR PTR PROADD
MAIN ENDP
第6章
子程序结构
PROADD PUSH PUSH PUSH LEA MOV XOR
REPEAT
;继续,键入Ctrl+Break返回DOS
第6章
子程序结构
RET
MAIN DECIBIN ENDP PROC NEAR