汇编返回指令ret iret retf区别

这是 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(段内调用)

示例:

cpp 复制代码
    CALL NEAR func    ; 压入 IP
    ...
func:
    RET               ; 弹出 IP,返回调用处

2. RETF (Return from Far Call)

操作:

cpp 复制代码
IP ← [SP]      ; 先弹出 IP
SP ← SP + 2
CS ← [SP]      ; 再弹出 CS
SP ← SP + 2

特点:

  • 恢复 IP 和 CS(实现段间跳转)

  • 不恢复 FLAGS

对应调用: CALL FAR(段间调用)或手动 PUSH CS + PUSH IP + RETF

你的监控程序中的例子(源码第 552 行):

cpp 复制代码
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)

操作:

cpp 复制代码
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 后的栈

cpp 复制代码
执行 CALL func 前              执行 CALL func 后
SP → [旧数据]                  SP → [返回 IP(2 字节)]
                               SP+2 → [旧数据]

执行 CALL FAR 后的栈

cpp 复制代码
执行 CALL FAR func 前          执行 CALL FAR func 后
SP → [旧数据]                  SP → [返回 IP(2 字节)]
                               SP+2 → [返回 CS(2 字节)]
                               SP+4 → [旧数据]

执行 INT n 后的栈

cpp 复制代码
执行 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 → RET

  • CALL FAR → RETF

  • INT n → IRET

相关推荐
半杯咖啡半行码4 小时前
STM32之ARM通用汇编指令详解:从指令格式到寻址方式
汇编·arm开发·stm32
Seeing510 小时前
音乐111111
汇编
Funlang10 小时前
从汇编到Fun语言
汇编
l1t14 小时前
DeepSeek总结的有符号、无符号、未对齐:从汇编到 SQL 的教训
汇编·数据库·sql
iCxhust5 天前
8088的nmi中断能关闭吗?
嵌入式硬件·8088单板机
Hi202402176 天前
同一个 NMS 算子,两种语言实现:CUDA C 与 Rust 生成 LLVM IR 和 Vortex 汇编的差异
c语言·汇编·rust·gpgpu·vortex·cudac
lhbweilai6 天前
深挖FreeRTOS内核实现(二)
c语言·汇编·stm32·单片机
水饺编程7 天前
第1章:开发环境搭建,在 Windows 中安装 VS 2019
linux·c语言·汇编·visual studio
水饺编程8 天前
第1章:下载 Linux 0.12 内核
linux·c语言·汇编·ubuntu
水饺编程8 天前
第1章:开发环境搭建,在 Windows 中安装 Git
linux·c语言·汇编·git·ubuntu