主程序与子程序
调用语句CALL
-
CALL指令分成4种类型
-
-
- CALL子程序名 ;段内直接调用
-
-
-
- CALL far ptr子程序名; 段间直接调用
-
-
不是很常用的
-
-
- CALL r16
CALL WORD PTR m16;段内间接调用(IP发生改变)
- CALL r16
-
-
-
- CALL DWORD ptr mem;段间间接调用(存储器)
-
-
CALL指令需要保存返回地址:
-
- 段内调用——在同一代码段内进行, 也称近调用偏移地址IP入栈
SP←SP- 2, SS:[SP]←IP
- 段内调用——在同一代码段内进行, 也称近调用偏移地址IP入栈
-
- 段间调用——在不同代码段之间进行,也称远调用
段地址CS和偏移地址IP和入栈
SP←SP- 2, SS:[SP]←CS
SP←SP- 2, SS:[SP]←IP
- 段间调用——在不同代码段之间进行,也称远调用
返回指令RET
子程序返回指令
- 功能:弹出堆栈中由CALL指令压入的返回地址值,迫使CPU返回到主程序中CALL指令的下一条指令去继续执行,该指令常放在子程序的最后
- 说明:根据段内和段间、有无参数,具体分成4种情况
(1) RET ;无参数返回
(2) RET n ;有参数返回 n参数的作用
需要弹出CALL指令压入堆栈的返回地址
(3)段内返回——偏移地址IP出栈
IP←SS:[SP], SP←SP+2
(4)段间返回——偏移地址IP和段地址CS出栈
IP←SS:[SP], SP←SP+2
CS←SS:[SP], SP←SP+2
子程序的定义
使用过程定义语句:
过程名 PROC
…
过程名 ENDP
子程序结构
- 调用指令的执行过程
1、保护断点
将调用指令的下一条地址(断点)压入堆栈(CS,IP)
2、获得子程序的入口地址(label)
子程序第一条指令地址
3、执行子程序(程序员完成)
功能实现,参数的保存和恢复(CS,IP)
4、恢复断点
将断点的偏移地址弹出。 - 子程序(过程)调用应处理好三个问题
1、保护断点(CS,IP入栈及出栈)
2、保护现场:子程序中用到寄存器/存储器需要保护
3参数传递:
寄存器传递:速度快,参数少(寄存器就在CUP内部)
存储器传输(可存放的数据多)
堆栈传递
用寄存器传递参数
例:用子程序计算数组元素累加和
入口参数:CX=元素个数,BX=元素的偏移地址 DS:BX=数组的段地址:偏移地址
出口参数:AL=累加和
- 把参数存于约定的寄存器中,可以传值,也可以传址。
子程序对带有出口参数的寄存器不能保护和恢复(主程序视具体情况进行保护)
子程序对带有入口参数的寄存器可以保护,也可以不保护;但最好一致 - 使用寄存器传递参数时
带有入口参数的寄存器可以保护,也可以不保护;
带有出口参数的寄存器则一定不可保护和恢复;
其他与出口参数无关、而子程序中使用 的寄存器,子程序开始处应该保护,子程序结束、返回主程序之前应该恢复。
用变量传递参数
主程序和子程序直接采用同一个变量名共享同一个变量,实现参数的传递.不同模块间共享时,需要声明
Data segment
COUNT EQU 5
ARRAY DB 12H,25H,0F0H,0A3H,03
RESULT DB ?
Data ends
Code segment
assume cs:code, ds: data
start:mov ax,data
mov ds,ax
CALL CHECK
Code ends
End start
CHECK PROC
……
LEA BX,ARRAY
……
CHECK ENDP
用堆栈传递参数
主程序将子程序的入口参数压入堆栈,子程序从堆栈中取出参数
子程序将出口参数压入堆栈,主程序弹出堆栈取得它们
多用于数组操作
实
例子
- 存储器传递参数
将一个字节BCD码(十进制数)转换成二进制数
;使用寄存器:CX
;入口参数: AL存放两位BCD
;出口参数: AL存放二进制数
;调用其它子程序:无
BCD2BIN PROC FAR
PUSH CX
MOV CH,AL
AND CH,0FH
MOV CL,4
SHR AL,CL
MOV CL,10
MUL CL
ADD AL,CH
POP CX
RET
BCD2BIN ENDP
数据段定义两个字型数组,编程序实现数组分别求和(不计溢出),要求用子程序实现求和。
解:
DATA SEGMENT
ARY1 DW 100 DUP(?) ; 定义数组1
SUM1 DW ?;和
ARY2 DW 100 DUP(?) ;定义数组2
SUM2 DW ?;和
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX, DATA
MOV DS, AX
LEA SI, ARY1 ;数组1首地址,入口参数
MOV CX, (SUM1-ARY1)/2 ;数组1加操作次数,入口参数(数组1的长度即length ARY1。/2因为DW)
CALL SUB_SUM ;调用求和子程序
MOV SUM1,AX ;数组1之和送SUM1
LEA SI, ARY2 ;数组2首地址,入口参数
MOV CX, (SUM2-ARY2)/2 ;数组2加操作次数,入口参数
CALL SUB_SUM ;调用求和子程序
MOV SUM2,AX ;数组2之和送SUM2
MOV AH, 4CH
INT 21H
;子程序名 SUB_SUM
;功能:完成一个数组中元素的相加
;入口参数:数组首地址SI,数组元素相加的次数CX
;出口参数:相加结果存在AX中
;占用寄存器:AX
SUB_SUM PROC NEAR ;子程序
XOR AX, AX ;AX清0
L1: ADD AX, WORD PTR[SI] ;加数组元素
INC SI
INC SI ;以字为地址,SI要加2
LOOP L1 ;cx-1
RET ;子程序返回
SUB_SUM ENDP
CODE ENDS
END START