我看到两种不同的说法。单纯的ret指令是不是用栈中数据修改的ip,可是又说和call指令联用后,可以同时修改cs,ip,也就是说可以用于段间返回, 是这样的吗?原以为段间返回一定得用retf,如果真是可以用于段间返回,那还要retf干嘛?
不明白了。。
------解决方案--------------------------------------------------------
王爽书上基本都是基础(我已看过),在讲到子程序调用时,基本不是按照远近(段间和段内)调用来详细讲解.
鉴于您在看王爽的书,且似乎是对此问题不好自己实践.那么我就班门弄斧一下,希望对您有帮助...
这是个王爽典型程序,应该不难看懂.(自己再作点简单介绍...)
STACKS SEGMENT
db 32 dup (0)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,SS:STACKS
START:
MOV AX,STACKS
MOV SS,AX
MOV SP,32
CALL FAR PTR S_CALL ;FAR PTR,典型的远调用,CS,IP先后入栈保存.
MOV AH,4CH
INT 21H
S_CALL: ;子程序
RET ;就一个返回指令
NOP ;NOP-无效指令.在程序中没实际意义,这里用来是为了DEBUG时容易观察.
NOP
NOP
NOP
NOP
CODES ENDS
END START
将此程序编译成EXE文件后DEBUG(下面的代码都是在DEBUG窗口以标记方式实录下来的):
-u
0B68:0000 B8660B MOV AX,0B66
0B68:0003 8ED0 MOV SS,AX
0B68:0005 BC2000 MOV SP,0020
0B68:0008 9A1100680B CALL 0B68:0011
0B68:000D B44C MOV AH,4C
0B68:000F CD21 INT 21
0B68:0011 C3 RET;这里是RET,机器码:C3.
0B68:0012 90 NOP
0B68:0013 90 NOP
0B68:0014 90 NOP
0B68:0015 90 NOP
0B68:0016 90 NOP
可以从上面简要看出虽是CALL 0B68:0011(远调用),但子程序中RET依然被编译为RET(RETN-C3).
那么可不可以再进一步实证一下呢?!
那就再一步一步T下看看...
-r
AX=0000 BX=0000 CX=0037 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B56 ES=0B56 SS=0B66 CS=0B68 IP=0000 NV UP EI PL NZ NA PO NC
0B68:0000 B8660B MOV AX,0B66
-t
AX=0B66 BX=0000 CX=0037 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=0B56 ES=0B56 SS=0B66 CS=0B68 IP=0003 NV UP EI PL NZ NA PO NC
0B68:0003 8ED0 MOV SS,AX
-t
AX=0B66 BX=0000 CX=0037 DX=0000 SP=0020 BP=0000 SI=0000 DI=0000
DS=0B56 ES=0B56 SS=0B66 CS=0B68 IP=0008 NV UP EI PL NZ NA PO NC
0B68:0008 9A1100680B CALL 0B68:0011 ;SP=0020
-t
AX=0B66 BX=0000 CX=0037 DX=0000 SP=001C BP=0000 SI=0000 DI=0000
DS=0B56 ES=0B56 SS=0B66 CS=0B68 IP=0011 NV UP EI PL NZ NA PO NC
0B68:0011 C3 RET ;注意这里的SP,已-4,就是说PUSH了两个字的内容(PUSH了两下)
-d ss:0 1f
0B66:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0B66:0010 00 00 66 0B 00 00 11 00-68 0B 6D 05 0D 00 68 0B ..f.....h.m...h.
;SS:1E保存了CS,SS:1C保存了下条指令MOV AH,4C的偏移.
-t
AX=0B66 BX=0000 CX=0037 DX=0000 SP=001E BP=0000 SI=0000 DI=0000
DS=0B56 ES=0B56 SS=0B66 CS=0B68 IP=000D NV UP EI PL NZ NA PO NC
0B68:000D B44C MOV AH,4C
-t ;到这里已返回了,看!SP=1E,就是说只出栈了SS:1C保存的IP.SS:1E保存了CS没出栈
AX=4C66 BX=0000 CX=0037 DX=0000 SP=001E BP=0000 SI=0000 DI=0000
DS=0B56 ES=0B56 SS=0B66 CS=0B68 IP=000F NV UP EI PL NZ NA PO NC
0B68:000F CD21 INT 21
- 这就不T了,后面就回DOS了...
从上面DEBUG情况侧面来看,CALL时入栈了CS和IP,RET时只出栈了IP,也一个方面在证实RET不以CALL时的远近调用属性而改变自己的远近返回属性.
鉴于时间有限就不一一详细实例举证了...
有时间能检验的朋友可以多多实验,来进一步探讨...