用 clang --target=aarch64-linux-gnu --sysroot=/path/to/sysroot -static 编译可执行文件,并通过 file 命令确认含 statically linked;若动态链接,则需 qemu-aarch64 -l /path/to/sysroot 运行并确保 ld-linux-aarch64.so.1 存在。

直接用 qemu-aarch64(或对应架构的 qemu-xxx)跑起来就行,但必须确保目标二进制是静态链接或宿主机有对应动态库——否则会报 qemu: uncaught target signal 11 (Segmentation fault) 或 No such file or directory。
怎么确认你的 LLVM 交叉编译产物能被 QEMU 正确加载
LLVM 本身不自带完整工具链,你得用 clang 配合 --target= 和 --sysroot= 生成真正可运行的目标文件。常见错误是只加了 --target 却没指定 --sysroot,结果链接了宿主机的 libc.so.6,而 QEMU 用户模式根本找不到 ARM 版本的动态链接器路径。
- 正确做法:用
clang --target=aarch64-linux-gnu --sysroot=/path/to/sysroot -static hello.c -o hello生成纯静态可执行文件(最省事) - 或者用
clang --target=aarch64-linux-gnu --sysroot=/path/to/sysroot --gcc-toolchain=/path/to/gcc-toolchain hello.c -o hello,再确保/path/to/sysroot下有lib/ld-linux-aarch64.so.1 - 验证是否静态:运行
file hello,输出含statically linked才安全;若显示dynamically linked,就得查readelf -l hello | grep interpreter看它想找哪个动态链接器
QEMU 启动时卡住或报 No such file or directory 怎么办
这不是程序崩溃,而是 QEMU 找不到目标平台的动态链接器(ld-linux-*.so.*)或基础共享库(libc.so.6)。QEMU 用户模式不会自动挂载 sysroot,它只按二进制里记录的路径去宿主机文件系统里硬找。
- 最稳妥方案:加
-static编译,彻底绕过动态链接 - 次选方案:用
qemu-aarch64 -L /path/to/sysroot ./hello,让 QEMU 把/path/to/sysroot当作目标根目录(等价于 chroot) - 别信
qemu-aarch64 ./hello能自动猜路径——它不会读取--sysroot编译参数,也不会扫描环境变量 - 如果用了
-L还报错,检查/path/to/sysroot/lib/ld-linux-aarch64.so.1是否真实存在且权限可读
为什么用 clang --target 编译的程序,qemu-aarch64 有时仍无法单步调试
因为默认生成的 debug info 是 host 格式(DWARF on x86_64),GDB 连 QEMU 时可能解析失败,表现为 Cannot access memory at address 0x… 或断点不命中。
- 必须加
-g且确保clang输出的是标准 DWARF(不是 vendor-specific 格式),避免用-grecord-gcc-switches这类 GCC 风格选项 - 启动 GDB 前先确认:
qemu-aarch64 -g 1234 ./hello,再在另一终端运行aarch64-linux-gnu-gdb ./hello(注意:必须用匹配架构的 GDB,不是本地gdb) - 连接后执行
set architecture aarch64,再target remote :1234,否则寄存器视图会错乱 - 若仍无法读变量,尝试加
-fdebug-prefix-map=/build/path=.把编译路径映射为当前目录,避免 GDB 在宿主机上找不存在的源码路径
最容易被忽略的一点:LLVM 工具链生成的二进制,其 ELF e_machine 字段和 PT_INTERP 段必须与 QEMU 支持的子系统严格匹配——比如用 --target=armv7a-linux-gnueabihf 编译的,就不能用 qemu-aarch64 运行,得换 qemu-arm;差一个字母,QEMU 就直接拒绝加载。











