bochs 中文文档 下载 App

反汇编当前指令——实时看 CPU 正在跑什么机器码

u 命令基本用法

bochs:1> u                       # 反汇编当前 EIP 指向的一条指令
bochs:2> u 0x7c00                # 反汇编指定地址的一条
bochs:3> u 0x7c00 16             # 从指定地址开始反汇编 16 条指令

输出示例(Bootloader 入口):

bochs:1> u 0x7c00
0000000000007c00: jmp .+0x16       (0x7c18)
0000000000007c02: xor ax, ax
0000000000007c04: mov ds, ax
0000000000007c06: mov es, ax
0000000000007c08: mov ss, ax
0000000000007c0a: mov sp, 0x7c00
...

每行格式:<物理地址>: <mnemonic> <operands>

反汇编器能力范围

Bochs 内置的反汇编器覆盖:

限制:

32 位 vs 64 位反汇编

Bochs 自动根据当前 CPU 模式(实模式/保护模式/长模式)选择反汇编的指令长度和语义:

实模式(16 位代码段)

bochs:1> u
0000000000007c00: jmp .+0x16       (0x7c18)      ← 相对跳转,16 位操作数
0000000000007c02: mov sp, 0x7c00                ← 16 位 sp

保护模式(32 位代码段)

bochs:1> u
00000000c0100000: mov eax, 0x12345678           ← 32 位操作数
00000000c0100005: call 0xc0100100                ← 32 位跳转

长模式(64 位代码段)

bochs:1> u
0000000000100000: mov rax, 0xdeadbeef           ← 64 位操作数,REX.W 前缀
0000000000100007: mov rdi, rax                   ← REX.R + REX.W 前缀

Bochs 反汇编器会正确处理 REX 前缀——你不会看到单独一行 rex,而是直接合并到反汇编结果里。

和 objdump 的对比

内核编译时 objdump -d 可以反汇编内核二进制文件里的所有函数,GDB 可以在运行时反汇编。Bochs 的 u 命令的独特价值是:

  1. 能看到运行时的指令——objdump 看到的是编译出来的静态指令;Bochs 看到的是CPU 当前正在执行的那条(包括内核自己在运行时写入的动态代码)
  2. 不依赖内核源码——甚至不依赖内核——Bootloader 刚加载完、内核还没启动时就能反汇编
  3. 不依赖 ELF/DWARF——纯粹看机器码,对任何裸机代码都能反汇编

OS 开发的典型工作流:

# 1. 宿主上反汇编内核二进制
objdump -d kernel.bin > kernel.asm

# 2. Bochs 里下断点到内核入口
bochs:1> vb 0xc0100000
bochs:2> c

# 3. 断点触发后,Bochs 里反汇编 + 宿主 objdump 交叉对照
bochs:3> u 0xc0100000 20

undisasm:每步都反汇编

undisasm on 让 Bochs 每条指令执行前都反汇编并打印:

bochs:1> undisasm on
bochs:2> c
Next at t=12350
(0) [0x0000000000007c02] 0000:7c02: xor ax, ax
Next at t=12351
(0) [0x0000000000007c04] 0000:7c04: mov ds, ax
...

极慢(每条指令都要反汇编+打印),但极其有用——当你想"让 CPU 跑一会儿,我看看它干了什么"时,开启 undisasm 然后让它跑几百条指令(Ctrl+C 随时中断),输出里能看到完整的执行轨迹。

undisasm off 关闭。

trace:更重的追踪

trace on 每执行一条指令都打印寄存器状态+反汇编——比 undisasm 输出更多。bochsrc 里也可以配置 trace 模式自动开启。但对于 OS 开发通常不需要这么重,undisasm 足够了。

手动汇编:db / asm(进阶)

Bochs 调试器有一个隐藏能力——可以在调试器里直接汇编指令并写入内存:

bochs:1> asm 0x7c00
asm> jmp short $
asm> ^D          # Ctrl+D 结束输入
# Bochs 汇编你的输入并写入 0x7c00
bochs:2> u 0x7c00
0000000000007c00: jmp 0x7c00

这在调试"我想快速试一条指令看看效果"的场景非常方便——不需要汇编、链接、写入磁盘、重启 Bochs 这一整套流程。

反汇编常见问题

反汇编结果里出现 "invalid"

Bochs 反汇编器无法识别当前位置的指令——可能原因:

  1. 内存里放的不是代码(是数据被误解码成指令)
  2. 指令编码用了 Bochs 反汇编器不支持的前缀(某些非常新的 AVX-512 变体)
  3. 反汇编起始地址对齐问题(从一条指令的中间开始反汇编)

想反汇编更大范围的代码块

bochs:1> u 0x7c00 1000     # 反汇编 1000 条指令(可能几千行输出)

输出会刷屏,建议用 bochsrc 里的 debugger_log 把输出记录到文件,然后在宿主上慢慢看。

debugger_log: bochs-trace.log