x86-64 与 AMD64 支持——从 32 位到 64 位的关键扩展
什么是 x86-64
x86-64(AMD 叫 AMD64,Intel 叫 EM64T)是 x86 架构从 32 位扩展到 64 位的路线。与 Intel 自己的 Itanium(IA-64)不同,x86-64 是向后兼容的——能直接跑 32 位 x86 代码,也能跑新的 64 位代码。
Bochs 对 x86-64 的模拟实现了完整的 64 位模式行为,OS 开发者可以用 Bochs 调试 64 位内核。
编译开关
x86-64 支持默认关闭,编译时必须显式开启:
./configure --enable-x86-64
编译完在 bochsdbg 里运行 show feature 确认:
bochs:1> show feature
feature: x86-64
没开的话 Bochs 模拟的 CPU(哪怕 model=pentium4)也不会进 64 位模式。
bochsrc 里的 CPU model
开了 x86-64 编译开关后,bochsrc 里 CPU model 选 pentium4 或更高就会有 64 位能力:
cpu: model=pentium4, count=1, ips=15000000
Bochs 会自动在 CPUID 里暴露 EM64T 标志,操作系统就能检测到支持 64 位模式。
如果选 model=coreduo、model=nehalem 等更新的型号,还会额外暴露 SSE3、SSSE3、SSE4、VT-x 等扩展。
x86-64 关键变化
通用寄存器:8 个变 16 个
| 旧名(32 位) | 新名(64 位) |
|---|---|
| EAX | RAX |
| EBX | RBX |
| ECX | RCX |
| EDX | RDX |
| ESI | RSI |
| EDI | RDI |
| EBP | RBP |
| ESP | RSP |
| — | R8 ~ R15(新增) |
新增的 R8-R15 寄存器没有 32 位别名,但可以用 R8D-R15D(32 位低半)、R8W-R15W(16 位低半)、R8B-R15B(8 位低半)访问。Bochs 调试器的 info registers 会全部显示。
地址空间:32 位变 64 位
32 位下每个进程虚拟地址空间 4GB,内核和用户共享地址空间;x86-64 下:
- 用户地址空间:0x0000000000000000 ~ 0x00007fffffffffff(128TB,目前硬件实际只用低 48 位)
- 内核地址空间:0xffff800000000000 ~ 0xffffffffffffffff(128TB)
Bochs 完整模拟这个地址空间分割。调试内核页表时 CR3 指向的 PML4 表、四个级别的页表遍历都和真实硬件一致。
REX 前缀
所有访问 R8-R15 或 64 位寄存器的指令都需要一个 REX 前缀(编码在 opcode 之前的 4 位标志)。这是 x86-64 引入的新机制,Bochs 的指令解码器完整实现了它。
OS 开发者在看 64 位反汇编时会频繁看到这个前缀。Bochs 的 u(disassemble)命令会正确把 REX 前缀解析出来,不会把它当作一条独立指令。
syscall / sysret
x86-64 引入了新的快速系统调用指令 syscall / sysret,替代了老的 int 0x80 / iret(int 0x80 在 64 位模式下仍然可用但慢得多)。
Bochs 正确模拟 syscall 行为:
- 从 RCX 取返回地址、从 R11 取旧 RFLAGS 保存到内核
- 跳转到 STAR_MSR 寄存器指定的内核入口
- sysret 时恢复地址和标志
调试器里在 syscall 上下断点可以追踪每一次系统调用。
FS/GS 段寄存器的角色变化
64 位模式下 CS/DS/ES/SS 段寄存器被"弱化"(变成"空选择子",段基址强制为 0、段限强制为最大值),但 FS 和 GS 被强化——内核可以用它们放 per-CPU 数据(Linux 里 GS 指向 per-CPU 区域)。
Bochs 正确模拟 FS/GS 的 64 位段基址——通过 wrmsr 指令写入 FS_BASE / GS_BASE MSR 来设置。
调试器里怎么看 64 位寄存器
在 bochsdbg 里:
bochs:1> info registers
CPU0:
rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rbp=0000000000000000 rsp=0000000000000000
r8=0000000000000000 r9=0000000000000000 r10=0000000000000000
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
rip=0000000000000000 eflags=00000002
64 位模式下所有寄存器都是 64 位宽,调试器显示时用 16 进制。
32 位和 64 位的互操作
Bochs 在 x86-64 模式下同时支持:
- 64 位长模式(Long Mode):完整 64 位地址 + 16 个寄存器
- 兼容模式(Compatibility Mode):进程地址空间里跑 32 位 x86 代码(类似 IA-32)
- 传统模式(Legacy Mode):开机时默认 32 位
内核从传统模式切换到长模式的经典步骤(OS 开发者必过):打开 CR4.PAE → 打开 CR0.PG → 加载 PAE 页表 → 打开 EFER.LMA → 跳转清除预取队列。Bochs 完整支持这条路径,可以在每一步下断点验证寄存器状态。