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

x86实模式下远跳转操作错误定位问题求助

问题分析与解决

你的问题核心是引导扇区复制到0x90000后,远跳转指令执行结果不符合预期,实际跳转到0x0001C而非0x9001C。以下是具体分析和修复方案:

关键问题排查

1. 注释未闭合导致代码失效

看go:标签后的注释:

/* now we are in the 0x90000
mov %ax, %cs
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov $0xffff, %sp

这段注释缺少闭合的*/,导致后续设置段寄存器的代码被全部注释。虽然这不是跳转错误的直接原因,但会导致后续访问数据时使用原段地址(0x07C0),而非新段地址(0x9000),引发潜在问题。

2. GDB反汇编的误导

调试输出中x/4i 0x7c17的反汇编结果是错误的,因为GDB默认按32位模式解析指令,而你的代码是16位实模式。查看机器码0xea 0x1c 0x00 0x00 0x90,这是正确的16位远跳转指令:

  • ea:16位远跳转操作码
  • 0x1c 0x00:小端序的IP偏移(0x001C)
  • 0x00 0x90:小端序的CS段值(0x9000)
    对应的线性地址是0x9000*16 + 0x001C = 0x9001C,指令本身是正确的。

3. 跳转后段寄存器未正确设置

虽然远跳转已经将CS设置为0x9000,但DS、ES、SS仍保留原段值0x07C0,后续访问boot_dirver、packet等数据时会访问原引导扇区地址,而非复制后的新地址。此外,直接mov %ax, %cs是非法操作,实模式下CS只能通过跳转、调用指令修改。

修复方案

1. 修复注释,正确设置段寄存器

将go:后的注释闭合,并移除非法的mov %ax, %cs指令,正确设置段寄存器:

go:
    /* now we are in the 0x90000 */
    mov $0x9000, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %ss
    mov $0xffff, %sp

    mov $20, %cx
    mov $msg_boot, %ax
    call print_msg

2. 验证跳转后的寄存器状态

在GDB中执行跳转后,使用info registers查看CS和IP的值,确认是否为cs 0x9000、ip 0x001c。如果是,说明跳转实际正确,GDB的地址显示是因为未识别实模式导致的误导。

3. 确认复制操作正确性

在跳转前,对比原地址和目标地址的内容,确保复制完整:

x/512b 0x7c00
x/512b 0x90000

如果两段内容完全一致,说明复制操作正确。

4. 正确生成16位指令

确保汇编器正确生成16位指令,使用GAS时,可在代码开头添加.code16并指定入口:

.code16
.global start
start:
    mov $0x07c0, %ax
    mov %ax, %ds
    ...

额外注意事项

  • 实模式下访问数据时,必须确保DS/ES等段寄存器指向正确的段地址,避免访问原引导扇区数据。
  • 远跳转指令会自动刷新指令流水线,无需额外操作。
  • 0x90000属于1MB以内地址,无需开启A20线即可访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:54:36