bochs 中文文档 下载 App

内存查看与修改——物理内存、虚拟内存和格式后缀详解

x vs xp:物理 vs 虚拟

命令含义地址类型翻译方式
xpeXamine Physical物理地址直接访问,无翻译
xeXamine(虚拟)虚拟地址通过当前 CR3 页表翻译

OS 开发优先用 xp——内核启动早期分页没开,虚拟地址 = 物理地址;分页开启后,xp 依然能绕过页表直接看物理内存,调试页表错误时反而更有用。

格式后缀控制显示方式

基本语法:x /<count><format><size> <address>

格式字符

字符含义
x十六进制(默认)
d十进制(带符号)
u十进制(无符号)
o八进制
cASCII 字符(不可打印显示 .)
s字符串(以 null 结尾)
i反汇编指令(和 u 命令效果相同)

大小字符

字符字节数C 类型
b1unsigned char
h2short
w2(注意:在 Bochs 里 w = 2 字节)word
g4dword
l4long
q8quad

注意:Bochs 的大小字符和 GDB 略有不同。b、w、l 分别是 1/2/4 字节,q 是 8 字节。别混用了。

常用示例

查看 Bootloader 引导扇区(物理)

bochs:1> xp /512bx 0x7c00       # 0x7c00 开始,512 字节十六进制

Bootloader 引导扇区的最后两字节(偏移 0x1FE, 0x1FF)必须是 0x55 0xAA——BIOS 才认它是可引导扇区。在输出的最后两行检查:

...
0x00007dfe: 55 aa ...

如果不是 0x55AA,你的 Bootloader 不会被 BIOS 加载。

查看 IDT(中断描述符表)

bochs:1> info sreg              # 先看 IDTR 的值
idtr=000000007c253c00           # 这是 IDT 的物理基址 + 段限
bochs:2> xp /16gx 0x7c253c00    # 看 IDT 的前 16 个条目(每个 8 字节)

查看虚拟地址对应的物理内存

bochs:1> vb 0xc0100000          # 给内核入口下虚拟断点
bochs:2> c                      # 运行到断点
bochs:3> x /8lx 0xc0100000      # 用 x 看虚拟地址(内核代码)
bochs:4> xp /8lx <物理地址>      # 用 xp 看翻译后的物理地址

写内存(wx 和 w)

bochs:1> wx 0x7c00 0xEB         # 物理地址 0x7c00 写入 0xEB(jmp short 指令)
bochs:2> wx 0x7c01 0xFE         # 下一字节:跳转 -2 偏移(0xFE = -2 的补码)
bochs:3> w 0xc0100000 0x48      # 虚拟地址写入(内核会通过 CR3 翻译)

写入的立即数可以是 1/2/4/8 字节——Bochs 根据值的范围自动决定大小,或者加后缀强制:

bochs:1> wx /4bx 0x7c00 0x00 0x00 0x00 0x00   # 写 4 个 0

搜索内存

Bochs 调试器没有内置搜索命令,但可以用 format 后缀组合变通——把内存当字符看:

bochs:1> xp /128cx 0x7c00       # 以字符方式看 128 字节
# 输出里 ASCII 字符会直接显示,方便找字符串常量

GDB 有 find/grep 命令,Bochs 没有。对于 OS 开发者来说,通常的做法是手动 dump 感兴趣的内存范围、用 HxD 或 objdump 在宿主上搜索。

虚拟地址翻译失败怎么办

用 x 命令时,如果 CR3 指向的页表里没有该虚拟地址的映射,Bochs 会提示:

bochs:1> x 0xdeadbeef
Cannot translate virtual address 0xdeadbeef to physical: page not present

常见原因:

  1. 内核还没初始化这个地址的页表(正确,继续调)
  2. CR3 写错了(内核 bug,需要调 CR3 赋值代码)
  3. 这个地址真的不存在(用 xp 绕过,直接看物理内存)

页表查看进阶:walk page table

Bochs 调试器有一个隐藏的"walk page table"能力——你可以手动跟踪 CR3 → PML4 → PDPT → PD → PT → 物理页的完整路径。

32 位 PAE 模式下:

bochs:1> info cr
cr3=0x12345000                  # PML4 基址(低 20 位是物理页号)
bochs:2> xp /4bx 0x12345000 + (虚拟地址>>39 & 0x1ff)*8
# 依次跟踪每一级表...

这很繁琐,但在调试内核页表初始化 bug 时是必要的。比如"用户进程访问一个地址触发 page fault,但你确信应该有映射"——就得手动 walk page table 看哪一级表项写错了。

内存检查清单(OS 开发场景)

检查目标命令说明
Bootloader 入口xp /512bx 0x7c00最后两字节 0x55AA
中断向量表(实模式)xp /256gx 0x0实模式 IVT 在物理 0x0
IDT(保护模式)先用 info sreg 找 IDTR,再 xp 看基址
GDT同上,用 info sreg 找 GDTR
内核入口内核编译地址 → x 看虚拟,xp 看物理
栈info registers rsp 找栈顶,xp 看栈内容
VGA VRAMxp /256bx 0xa0000显存起始地址
BIOS 区域xp /256bx 0xfffc0000ROM BIOS