这是 8086 汇编中三个最容易混淆的返回指令。它们的区别在于从栈上弹出什么数据以及如何恢复 CPU 执行状态。
核心区别一览表
| 指令 | 操作码 | 弹出字节数 | 弹出的内容 | 典型配对 | 使用场景 |
|---|---|---|---|---|---|
RET | C3 | 2 | IP | CALL NEAR | 段内返回 |
RETF | CB | 4 | IP→CS | CALL FAR | 段间返回 |
IRET | CF | 6 | IP→CS→FLAGS | INT n | 中断返回 |
详细分析
1. RET (Return from Near Call)
操作:
IP ← [SP] SP ← SP + 2特点:
只恢复指令指针 IP
不改变 CS(仍在同一代码段)
不恢复 FLAGS
对应调用:CALL NEAR(段内调用)
示例:
CALL NEAR func ; 压入 IP ... func: RET ; 弹出 IP,返回调用处2. RETF (Return from Far Call)
操作:
IP ← [SP] ; 先弹出 IP SP ← SP + 2 CS ← [SP] ; 再弹出 CS SP ← SP + 2特点:
恢复IP和CS(实现段间跳转)
不恢复 FLAGS
对应调用:CALL FAR(段间调用)或手动PUSH CS+PUSH IP+RETF
你的监控程序中的例子(源码第 552 行):
522 C287 A108FF MOV AX,[USER_CS] ; AX = 0000H 523 C28A 50 PUSH AX ; 压入 CS 524 C28B A106FF MOV AX,[USER_IP] ; AX = 0400H 525 C28E 50 PUSH AX ; 压入 IP ...(恢复其他寄存器) 552 C2B2 CB RETF ; 弹出 IP=0400, 弹出 CS=0000 ; 跳转到 0000:0400(用户程序)3. IRET (Return from Interrupt)
操作:
IP ← [SP] ; 弹出 IP SP ← SP + 2 CS ← [SP] ; 弹出 CS SP ← SP + 2 FLAGS ← [SP] ; 弹出 FLAGS SP ← SP + 2特点:
恢复IP、CS和FLAGS
通常还会恢复中断允许标志(IF)(因为
INT指令会自动清除 IF)
对应调用:INT n(软件中断)或硬件中断
栈帧对比图
执行 CALL NEAR 后的栈
执行 CALL func 前 执行 CALL func 后 SP → [旧数据] SP → [返回 IP(2 字节)] SP+2 → [旧数据]执行 CALL FAR 后的栈
执行 CALL FAR func 前 执行 CALL FAR func 后 SP → [旧数据] SP → [返回 IP(2 字节)] SP+2 → [返回 CS(2 字节)] SP+4 → [旧数据]执行 INT n 后的栈
执行 INT n 前 执行 INT n 后 SP → [旧数据] SP → [返回 IP(2 字节)] SP+2 → [返回 CS(2 字节)] SP+4 → [FLAGS(2 字节)] SP+6 → [旧数据]常见错误
❌用RET代替IRET:会导致 FLAGS 没有被弹出,栈不平衡,返回地址错误
❌用IRET代替RET:会多弹出 2 字节当作 FLAGS,导致 IP 和 CS 错位
❌用RETF代替IRET:FLAGS 没有被恢复,中断标志可能错误
✅正确原则:用什么指令调用,就用对应的指令返回
CALL NEAR→RETCALL FAR→RETFINT n→IRET