昨天遇到一个奇怪的问题, 上网搜索没找到有用的回答. 今天偶然解决了, 希望通过记录解决方法, 为以后提供帮助吧.

问题

  1. 同样的原版 xv6 (b818915), make qemu 在笔记本上可以运行, PC 上一直刷新 Booting from hard disk.

求解

  1. qemu 版本 / gcc 版本?
    • 在 PC 上编译不同版本的 qemu, 开启或关闭 KVM, 尝试 canonical 源的 qemu. 都是同样结果
    • 笔记本和 PC 上 qemu 都是 2.5, 笔记本可以, PC 不行
    • 笔记本使用 gcc-5.4, 在 PC 上切换成 gcc-5.4 也不行
    • 笔记本编译出的镜像可以在 PC 上运行; PC 编译出的镜像在笔记本上不能运行, 同样错误.
  2. 结论: 应该是编译环境的问题. 检查用到的所有工具
    $ make clean
    $ make qemu -n | cut -d\  -f1 | sort | uniq
    #
    dd
    gcc
    ld
    ./mkfs
    objcopy
    objdump
    qemu-system-i386
    ./sign.pl
    ./vectors.pl
    
  3. 排查过 qemu 和 gcc 应该不是问题, 重点放到了 binutils.
    • objcopy / objdump 的版本完全一样
    • ld: 版本一样, 但是发现 PC 上用了 ld.gold, 笔记本用的 ld.bfd.
  4. 在 PC 上, 将 ld 切换成 ld.bfd 之后 make qemu 也能正常运行了.

关于 gold

gold 是另外的 linker, 比默认的 bfd 更快更省内存, 尤其是编译大型 C++ 项目的时候.

根据男人, gold 是 the GNU ELF linker, 而 bfd 是 the GNU linker.

另外一些信息如

gold 的作者写了一堆关于 linker 的 blog.

其他

前几天遇到类似的问题, 在一个学生的电脑上, qemu (riscv) 运行某 奇怪操作系统 也是卡在 booting from hard disk.

这次原因又是 qemu 的问题了 – 我把我的 qemu 给他就好了.

后来又遇到类似的问题. 这次是, 同样的 kernel image. 我在 ubuntu 上运行, 然后另外的人可以在他的 ubuntu 上运行. 但另外的人无法在他的 mac OS 上运行. 我怀疑是 qemu 版本, 但都是 3.10. 加上 mac OS 似乎无法直接运行我给他的 ELF, 所以只好让他在 ubuntu 上开发.

之后遇到其他的问题, 这次是因为在内核中访问了非法地址 i.e. 内核中 pagefault. 可以在 xv6 的 main 中加入一行 while (*(int*) 0xDEADBEE0) ; 来复现这个错误.

如果想要防止 qemu 不断重启, 可以加入选项 -no-reboot.