为什么要在M1芯片上折腾ucore?

M1芯片是2020年之后推出的全新适配于Macbook的Arm64芯片。因为底层的指令集与x86_64不同,因此面临着很多兼容性的问题。截止开始写博文的时候,M1芯片已经经历了接近2年的磨合期,日趋完善。

ucore是清华大学为计算机专业本科生提供的微型操作系统内核,代码是基于x86架构编写的。麻雀虽小五脏俱全,覆盖了内核的主要机制。通过改写ucore,可谓学习操作系统原理的不二法门。

之所以要在M1芯片上进行ucore的开发,调试,主要因为Macbook因为其良好的工作体验已经成为很多程序员离不开的工作机器,而M1芯片目前并不支持虚拟机产品运行x86系统(当然qemu目前已经支持,但基于软件实现,效率非常低)。因此如果想用M1来开发调试ucore,一定会涉及到交叉编译的问题。

因此作者花了一下午的时间,终于搞定了在基于M1芯片的Macbook上进行ucore的编译,运行和调试。写下这篇文章分享给大家我的方案。

准备相关工具

qemu

qemu是非常成熟的虚拟化解决方案,通过软件的方式逐条将目标文件的二进制指令翻译成目标架构支持的二进制指令,虽然效率不高,但是使用方便,对M1芯片支持十分完善,足够用来调试ucore了。

# 安装homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 安装qemu
brew install qemu

交叉编译工具gcc

交叉编译意味着我们在某一架构上编译另一架构的目标文件(可以使lib,也可以是可执行文件)。因为最终编译的指令集不同,虽然可以根据高级语言和汇编语言编译相应的目标文件,但是并不能在开发者使用的架构上运行目标文件。

在编译ucore中,我们所在的架构师Arm64架构,目标架构是i386架构。按理来说应该用i386架构下的gcc进行编译,然而M1芯片已经不支持32位的编译器,所以只能安装可以将源码编译为x86_64指令的编译工具(x86_64兼容i386)。

在MacOS中可以使用homebrew安装x86_64-elf-gcc进行编译brew install x86_64-elf-gcc

调试工具

和gcc一样,也要安装x86_64的调试程序x86_64-elf-gdb,同样也是使用homebrew。我不是没有试过原装的lldb,但是在连接qemu的时候会出现error: failed to get reply to handshake packet的报错。如果有兴趣的同学可以研究一下,我就不搞了。

编译

准备好所有的工具,就可以开始编译ucore了,进入labcodes/lab1目录下。

首先需要修改Makefile文件,虽然HOSTCFLAGS中设置了-g的标志,但是同样也指定了代码优化等级为-O2,个人认为改为-O0比较合适。

执行下面的指令make GCCPREFIX=x86_64-elf-,主要是指定交叉编译工具。因为代码比较简单,很快就可以编译成功,也不会有什么坑。

运行和调试

切换到labcodes/lab1,在bin目录下,会出现4个文件,其中kernel中包含了可执行文件的符号表,用来调试用的。而.img文件是系统镜像。

因为ucore是一个基于i386编写的内核,因此必须要用qemu-system-i386才能正确运行。

qemu-system-i386 -S -s -hda bin/ucore.img -monitor stdio

因为-S -s的标记,系统并没有启动,需要用gdb来启动系统。按照下面的流程逐一执行,就可以看到系统停留在断点memset处,执行continue,操作系统将会启动,并在qemu窗口不断打印
100 ticks

$ x86_64-elf-gdb
GNU gdb (GDB) 12.1
(gdb) file bin/kernel 
Reading symbols from bin/kernel...
(gdb) target remote :1234
Remote debugging using :1234
0x0000fff0 in ?? ()
(gdb) b memset
Breakpoint 1 at 0x1032c2: file libs/string.c, line 271.
(gdb) c
Continuing.

Breakpoint 1, memset (s=0x10fa16, c=0 '\000', n=4850) at libs/string.c:271
271     memset(void *s, char c, size_t n) {
(gdb) c
Continuing.

总结

本文介绍了如何使用交叉编译的方式在使用M1芯片的Macbook上进行ucore的编译,运行和调试。过程中需要踩几个交叉编译和跨平台调试的坑。借助qemu虚拟化,在Arm64芯片上运行x86_64架构的系统内核。


侯磊
13 声望5 粉丝