●
CALL SUBROUT 段内直接调用
执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
② (IP) ← (IP)当前+16位位移量(在指令的第2、3个字节中)
● CALL DESTIN 段内间接调用
执行操作:① (SP) ← (SP)-2,((SP)) ← (IP)当前
② (IP) ← (EA) ; (EA)为指令寻址方式所确定的有效地址
● CALL FAR PTR SUBROUT 段间直接调用
执行操作:① (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,30
0003 BB 0028 MOV BX,40
0006 50 PUSH AX ; push data1 into stack
0007 53 PUSH BX ; push data2 into stack
0008 E8 0066 CALL ADDM ; call subroutine
000B B4 02 MOV AH,2
… … …
0071 ADDM PROC NEAR ; entry point (IP)←0071=000b+0066
0071 55 PUSH BP ; save BP
0072 8B E4 MOV BP,SP ; addressing the stack with BP
0074 8B 46 04 MOV AX,[BP+4] ; get data2 from stack
0077 03 46 06 ADD AX,[BP+6] ; add data1
007A CD POP BP ; get back BP
007B C2 0004 RET 4 ; return and revert SP
007E 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跳过了堆栈数据而回到了原始位置。