qemu 中文文档 下载 App

用户态模拟深入指令翻译与系统调用转发

用户态模拟 vs 系统模拟

快速回顾:

系统模拟用户态模拟
命令前缀qemu-system-xxxqemu-xxx
模拟范围完整硬件 + OS仅指令 + syscall
Guest OS完整引导不需要,宿主内核接管
用途跑另一个 OS跑另一个架构的单个程序

用户态模拟的命令行是 qemu-${arch},其中 arch 是目标架构:

qemu-aarch64      # 64 位 ARM
qemu-arm          # 32 位 ARM
qemu-riscv64      # 64 位 RISC-V
qemu-riscv32      # 32 位 RISC-V
qemu-mips64       # 64 位 MIPS
qemu-ppc64        # 64 位 PowerPC
qemu-x86_64       # 用户态 x86_64(模拟 x86 用户态,宿主可能不是 x86)

基本用法

直接运行

qemu-aarch64 ./hello-arm64
# Hello, ARM64 World!

QEMU 自动识别 ELF 文件的架构,用对应的指令翻译引擎执行。

带库路径

很多程序需要动态链接库。QEMU 默认找宿主的库,不对。用 -L 指定目标架构的根文件系统:

qemu-aarch64 \
  -L /opt/arm64-rootfs \
  ./my-arm64-app

QEMU 会在 /opt/arm64-rootfs/lib/ 下找 ARM64 的 .so 文件。

静态链接 vs 动态链接

推荐:嵌入式开发时用 -static 编译,避免依赖链。

系统调用转发

用户态模拟的核心机制是:Guest 二进制的 syscall 被 QEMU 拦截,然后转换成宿主内核的 syscall。

Guest ARM64 程序
    │
    │ syscall (ARM64 syscall 编号)
    ▼
QEMU 用户态模拟器
    │
    │ syscall 编号转换表
    ▼
宿主 Linux 内核 (x86_64)
    │
    ▼
返回值转回 ARM64 风格

syscall 编号映射

不同架构的 syscall 编号完全不同。sys_write:

QEMU 内部维护了一张映射表,把 Guest 编号转成宿主编号。这个映射表是架构相关的,内置在每个前端里。

syscall 兼容性限制

并非所有 syscall 都能完美转发:

QEMU 对这些情况有 fallback:用等价的老 syscall 替换,或返回 ENOSYS。

与 rootfs 配合使用

完整的用户态环境:

# 解压一个 ARM64 Debian rootfs
sudo debootstrap --arch=arm64 bookworm arm64-rootfs

# 用户态模拟跑 shell
qemu-aarch64 \
  -L ./arm64-rootfs \
  ./arm64-rootfs/bin/bash

# 现在你在 ARM64 的 bash 里,可以 apt update、安装软件

更干净的方式:binfmt_misc

在 Linux 上注册 binfmt ,让内核自动调用 QEMU:

# 注册 ARM64 ELF 格式
echo ':arm64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64-static:F' | sudo tee /proc/sys/fs/binfmt_misc/register

之后直接运行 ARM64 二进制:

./hello-arm64    # 内核自动调用 qemu-aarch64-static

用户态模拟的常见应用

1. 跨架构编译验证

# 编译 ARM64 二进制
aarch64-linux-gnu-gcc -static hello.c -o hello-arm64

# 快速验证
qemu-aarch64 ./hello-arm64

2. 逆向分析

在不搭建完整系统的情况下分析恶意软件:

# 带 strace 分析 syscall
qemu-aarch64-strace ./suspicious-arm64-binary

3. 嵌入式调试

配合 GDB:

qemu-aarch64 -g 1234 ./my-arm64-app
# 在另一个终端:
aarch64-linux-gnu-gdb ./my-arm64-app
(gdb) target remote :1234

4. Linux 内核单元测试

QEMU 用户态模拟是很多内核测试框架的基础(如 LTP、kselftest)。

用户态模拟 vs 其他跨架构工具

工具原理速度范围
QEMU userTCG 指令翻译 + syscall 转发中等通用
Box86/Box64x86→ARM/RISC-V 翻译较快仅 x86
Rosetta 2ARM64→x86 硬件辅助很高仅 macOS
FEX-Emux86→ARM64 动态翻译高仅 x86

下一步

用户态模拟理解了,继续跳到 VM 管理与热迁移 或 性能调优。