You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从32位保护模式返回实模式:是否可省略远跳转指令?

从32位保护模式返回实模式:能否省略远跳转指令?

我正在从32位保护模式返回实模式,参考的代码里包含一条远跳转指令,我的当前代码如下:

; At this point we are still in protected mode with CS pointing
    ; to a 16-bit descriptor.
    bits 16
    cli  ; Just to make sure.
    mov eax, cr0
    and eax, 0x7FFFFFFe ; Disable paging bit & disable 16-bit pmode.
    mov cr0, eax
f1: jmp 0:GoRMode  ; ?? Is this far jump needed ??
GoRMode:
    mov sp, 0x8000
    mov ax, 0       ; Reset segment registers to 0.
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    pushf
    pop ax
    or ax, strict word 0x200  ; IF := 1 (sti) by the iret below.
    push ax
    push word my_segment
    push word my_offset
    iret  ; Pops IP first, then CS, then FLAGS.

我的核心问题是:能否省略这条远跳转指令而不引发异常?

我的思路是最终的iret指令会负责设置CS寄存器。我已在QEMU(含/不含KVM)、VirtualBox、v86及86Box(Intel 430VX芯片组、Pentium-S P54C 90MHz CPU)环境中测试,有无该远跳转指令代码均可正常运行,且已验证此场景下iret不会弹出SS和SP寄存器。

通过使用iret,我可避免中断过早触发的问题:仅当iret执行时才会启用中断,此时系统已完全进入实模式(即所有段寄存器均使用实模式描述符)。另外我知道可将末尾几条指令替换为sti+jmp my_segment:my_offset,但这可能因两条指令间触发中断而失效。


回答

可以省略这条远跳转指令,不会引发异常,原因如下:

  • 执行mov cr0, eax关闭保护模式位后,CPU进入实模式,但此时CS仍保留着之前的16位保护模式选择子。不过实模式下段寄存器的作用是直接作为段基址的高16位(左移4位),即便CS此时的数值是保护模式选择子,后续的iret指令会原子性地将CS设置为my_segment,直接覆盖原有值,因此中间的远跳转并非必需。
  • 你的多环境测试结果已经验证了这一点:无论是虚拟机还是硬件模拟器,省略远跳转后代码都能正常运行,说明这种做法具备兼容性。
  • 用iret来完成中断启用和跳转的方案确实更安全:iret会一次性设置FLAGS(包括IF位)和CS:IP,不存在sti和远跳转之间的中断触发窗口,避免了中断过早触发导致的问题。

内容的提问来源于stack exchange,提问作者pts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 12:43:26