学习操作系统有比较好的两种方式,第一种是跟着别人写一个操作系统出来,《操作系统真相还原》、《Orange's:一个操作系统的实现》等书就是教学这个的;另一种方式就是调试操作系统源码,相比第一种方式,调试源码可以更能感受真实操作系统的实现机制。
Linux-0.11 是 Linux 最早期的代码,它包含现代操作系统的所有雏形,代码体量也不大,非常适合对操作系统进行源码学习。下面记录在 Ubuntu22 上面编译调试源码的流程。
QEMU 是一款模拟器,它可以模拟 i386、x86_x64、ARM 等多种 CPU 架构,编译好的 Linux-0.11 代码就会跑在这个模拟器上。QEMU 的官网: https://www.qemu.org 。
在 Ubuntu20 以后安装 QEMU 的指令如下:
sudo apt-get install qemu sudo apt-get install qemu-system
下载安装好之后,在控制台输入 qemu-,按 Tab 键两次,就会显示所有支持的 CPU 架构:
由于 Linux-0.11 代码比较古老,直接从官网下载自己编译需要处理很多问题,好在前人已经帮我们做好了(感谢这些前辈),我们只需要到下面 github 地址上下载源码编译,就可以直接在 QEMU 上启动了。github 地址:
https://github.com/yuan-xy/Linux-0.11
下载好源码之后,进入根目录,直接运行下面的命令:
make start
就可以编译运行 Linux-0.11 操作系统了。运行效果如下面所示:
如果想 debug 源码,就直接运行下面的命令启动操作系统:
make debug
这时会弹出下面的窗口,整个系统处于 Paused 状态:
此时整个系统处于可以被调试的状态。开启一个新的控制台窗口,输入下面的命令:
gdb tools/system target remote:1234
就可以愉快的调试操作系统源码了。
比如我们想调试操作系统的 main 函数,就继续输入下面两行命令:
b main
c
此时 gdb 已经断在了操作系统的 main 函数上。
在使用 gdb 进行调试时需要注意,如果不修改 Linux-0.11 源码里面的 Makefile 文件,直接运行下面代码:
gdb tools/system target remote:1234
会报 ‘g' packet reply is too long 的错误,此时没法进行调试。
报错的原因上面第一个红箭头处已经提示了,Linux-0.11 编译后的二进制需要运行在 i386 架构上,但是现在确运行在了 x86_x64 架构上。
从 Linux-0.11 的 make 文件(Makefile.header)可以看到,Linux-0.11 被编译链接成32bit的程序:
上面的 CFLAGS 中的 -m32 以及 LDFLAGS 中的 -m elf_i386 就是编译链接成32位程序的指令。Linux-0.11 最终的编译产物位于 tools/system,通过在控制台使用 file 命令同样也可以看到:
要解决这个问题,只要找到 Linux-0.11 的 Makefile 文件(该文件包含 Makefile.header 文件),找到下面的命令:
将箭头处原本是 x86_64 替换成 i386 保存,重新执行调试命令即可。