一、子程序定義
子程序名 PROC NEAR|FAR
RET
子程序名 ENDP
子程序名相當(dāng)于標(biāo)號(hào),表示本過(guò)程的符號(hào)地址。過(guò)程有NEAR和FAR兩種類(lèi)型,F(xiàn)AR型的過(guò)程可供段間調(diào)用,NEAR型過(guò)程僅供段內(nèi)調(diào)用。
在一個(gè)過(guò)程中,至少要有一條返回指令RET,它可以書(shū)寫(xiě)在過(guò)程中的任何位置,但是過(guò)程執(zhí)行的的最后一條指令一定是RET。
二、子程序調(diào)用指令
格式:CALL [NEAR PTR] 子程序名
CALL指令的兩個(gè)作用,1.將斷點(diǎn)地址(CALL指令的下一條指令地址)壓棧保存,2.轉(zhuǎn)去子程序執(zhí)行。
[NEAR PTR]可以省略。
三、返回指令
格式:RET [N]
指令作用:實(shí)現(xiàn)子程序執(zhí)行完后返回主程序的指令。從堆棧棧頂彈出一個(gè)字?jǐn)?shù)據(jù)(段內(nèi)調(diào)用)送入IP作為返回地址。N是立即數(shù),執(zhí)行完RET之后,再將SP增加N,也叫“平?!?。
四、子程序參數(shù)傳遞的三種方式:
程序示例:假設(shè):N1=1234H,N2=2345H,N3=3456H,計(jì)算并顯示這3個(gè)數(shù)的累加和,并用二進(jìn)制形式顯示結(jié)果
1.通過(guò)寄存器傳遞參數(shù):調(diào)用子程序前,調(diào)用程序把入口參數(shù)放在約定的寄存器中,子程序執(zhí)行時(shí),通過(guò)約定的寄存器取得入口參數(shù);返回時(shí),子程序把出口參數(shù)存放在約定的寄存器中,調(diào)用程序通過(guò)約定的寄存器中取得出口參數(shù)。
DATA SEGMENT
NUM DW 1234H
DW 2345H
DW 3456H
DATA ENDS
STACKS SEGMENT STACK
DB 100 DUP(?)
STACKS ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACKS
BEG: MOV AX,DATA
MOV DS,AX
MOV SI,OFFSET NUM
CALL COMPUTE
XYZ: CALL DISP
MOV AH,4CH
INT 21H
COMPUTE PROC
MOV BX,0
ADD BX,[SI+0]
ADD BX,[SI+2]
ADD BX,[SI+4]
RET
COMPUTE ENDP
DISP PROC
MOV CX,16
LAST: MOV DL,'0'
RCL BX,1
JNC NEXT
MOV DL,'1'
NEXT: MOV AH,2
INT 21H
LOOP LAST
RET
DISP ENDP
CODE ENDS
END BEG
本例程序中調(diào)用程序把2號(hào)功能入口參數(shù)放在DL寄存器中,顯示子程序在執(zhí)行時(shí)從DL中取得參數(shù)。
2.通過(guò)堆棧傳遞參數(shù):子程序調(diào)用前,調(diào)用程序把參數(shù)依次壓入堆棧,構(gòu)成一個(gè)堆棧參數(shù)表,當(dāng)子程序調(diào)用時(shí),子程序從堆棧中取出各參數(shù)。子程序返回時(shí),要使用 RET n 指令調(diào)整SP指針,其中n是堆棧參數(shù)表的大小,即使用完堆棧之后刪除堆棧參數(shù)表,使堆棧恢復(fù)到原始狀態(tài),也就是文章開(kāi)始提到的“平?!薄?
DATA SEGMENT
NUM DW 1234H
DW 2345H
DW 3456H
DATA ENDS
STACKS SEGMENT STACK 'STACK'
DB 100 DUP(?)
STACKS ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACKS
BEG: MOV AX,DATA
MOV DS,AX
MOV SI,OFFSET NUM
PUSH WORD PTR [SI+0]
PUSH WORD PTR [SI+2]
PUSH WORD PTR [SI+4]
CALL COMPUTE ;注意CALL指令隱含的堆棧操作
XYZ: CALL DISP
MOV AH,4CH
INT 21H
COMPUTE PROC
MOV BP,SP
MOV BX,0
ADD BX,[BP+2] ;棧底處在高地址段
ADD BX,[BP+4]
ADD BX,[BP+6]
RET 6
COMPUTE ENDP
DISP PROC
MOV CX,16
LAST: MOV DL,'0'
RCL BX,1
ADC DL,0
NEXT: MOV AH,2
INT 21H
LOOP LAST
RET
DISP ENDP
CODE ENDS
END BEG
3.通過(guò)變量傳遞參數(shù):如果子程序和調(diào)用程序都在同一個(gè)源文件中,則雙方可以直接訪問(wèn)模塊中的變量,從而實(shí)現(xiàn)參數(shù)傳遞。
STACKS SEGMENT STACK 'STACK’
DB 100 DUP(?)
STACKS ENDS
CODE SEGMENT
ASSUME CS:CODE,SS:STACKS
BEG: CALL COMPUTE
NUM DW 1234H
DW 2345H
DW 3456H
XYZ: CALL DISP
EXIT: MOV AH,4CH
INT 21H
COMPUTE PROC
MOV BP,SP
MOV SI,[BP+0] ; [BP+0]為斷點(diǎn)地址
MOV BX,0
ADD BX,CS:[SI+0]
ADD BX,CS:[SI+2]
ADD BX,CS:[SI+4]
POP AX ;彈出原來(lái)的斷點(diǎn)地址
MOV AX,OFFSET XYZ ;改變棧頂內(nèi)容,從而使返回地址改變
PUSH AX
RET ;返回?cái)帱c(diǎn)XYZ
COMPUTE ENDP
DISP PROC
MOV CX,16
LAST: MOV AL,'0'
RCL BX,1
ADC AL,0
NEXT: MOV AH,0EH ;BIOS功能調(diào)用顯示一個(gè)字符
INT 10H
LOOP LAST
RET
DISP ENDP
CODE ENDS
END BEG
這個(gè)例子沒(méi)有我們常見(jiàn)的數(shù)據(jù)段,二是把數(shù)據(jù)定義在了代碼段,子程序在執(zhí)行時(shí),需要用數(shù)據(jù)時(shí),訪問(wèn)存放數(shù)據(jù)的內(nèi)存單元,并且在子程序執(zhí)行要結(jié)束時(shí),改變?cè)瓉?lái)的斷點(diǎn)地址,跳過(guò)代碼段中的數(shù)據(jù)存儲(chǔ)區(qū),到下一片段的執(zhí)行代碼區(qū)。