汇编返回指令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

相关推荐
水饺编程16 小时前
第2章:Linux 基础,解压缩【.tar.bz2】压缩包文件
linux·c语言·汇编
Zevalin爱灰灰16 小时前
Linux入门第二部分(ARM裸机篇) 第二章 Cortex-A7 MPCore架构与ARM汇编基础
linux·汇编·arm开发·嵌入式
Zevalin爱灰灰1 天前
Linux入门第二部分(ARM裸机篇) 第三章 汇编LED驱动实验
linux·汇编·arm开发
水饺编程2 天前
第2章:Linux 基础,制作【.tar.xz】压缩包文件
linux·c语言·汇编
小向是个Der4 天前
嵌入式进阶——编译与链接
汇编·单片机·学习·编译原理·交叉编译
二十七日秋4 天前
算法刷题笔记「Day 1|四道 OJ 入门题里的深坑」
c语言·汇编·数据结构·c++·笔记·python·算法
银河麒麟操作系统4 天前
两案例入选全球计算联盟年度产业应用案例汇编
大数据·汇编·人工智能
abc light4 天前
ARM 裸机开发(2)——ARM 汇编与启动代码
汇编·arm开发
soso19685 天前
Modbus协议开发实战指南
汇编
水饺编程6 天前
第2章:Linux 基础,解压缩【.tar.gz】压缩包
linux·c语言·汇编