这段时间在跟着教程https://github.com/cfenollosa/os-tutorial,把操作系统的知识通过跟项目的方式复习一下。昨天把bootloader部分结束,开始准备看kernel部分。看kernel部分之前有一节cross compiler setup,本以为像之前一样复制粘贴就行,但就是在这部分遇到了一些问题。

截至目前,如果大家用的是最新的MacOS系统,则按照它的教程,编译GCC时,会在运行命令make all-gcc时,遇到关键词为error: no member named ‘fancy_abort’ in namespace ‘std::__1’;的报错。报错原因和XCode package和gcc的兼容性有关,gcc 5之后修正了该问题,但教程非要4.9版本……之后翻看os-tutorial项目的pr,看到这个pr:https://github.com/cfenollosa/os-tutorial/pull/97。它介绍了通过brew,去直接安装cross compiler的方式。但作者很早就停止维护这个教程了(最后一次merge request发生在18年),所以这个本来很有价值的pr一直没被merge。用brew安装后,通过命令x86_64-elf-gcc唤起cross compiler即可。

之后读了个关于cross-compiler的教程:

https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler

并把要点提炼了一下:

为什么需要用cross-compiler:demo os kernel编写代码和运行的系统架构和对目前系统库的依赖可能不同,所以需要一个通过不同参数方式编译的gcc,来编译出适应于目标平台的内核代码。

macOS上运行gcc -dumpmachine命令的输出是x86_64-apple-darwin19.2.0,而对x86_64-elf-gcc运行上述命令的输出是x86_64-elf。显而易见为何需要搭建cross compiler环境了。

编译要带的选项:

  • -ffreestanding:让编译器知道它会用于编译kernel代码而不是用户代码。该模式下需要自己实现memset, memcpy, memcmp and memmove。
  • -mno-red-zone (x86_64 only):避免kernel处理中断时把栈弄乱。
  • -fno-exceptions, -fno-rtti (C++):如无必要,勿增实体。

链接要带的选项:

  • -nostdlib (same as both -nostartfiles -nodefaultlibs):要写kernel代码,所以适合于用户态的标准库不适用于kernel了,需要重写stdlib。
  • -lgcc:弥补前一个选项导致gcc lib被隐性地disable了,但链接时又需要其中的内容。

其他教程经常会胡搞的选项(不要给编译器传的):

  • -m32, -m64 (compiler),-melf_i386, -melf_x86_64 (linker),-32, -64 (assembler):简化makefile,cross-compiler自身能解决前四个选项解决的问题,build gcc前build binutils时已经解决了后两个选项解决的问题。
  • -nostdinc:需要头文件的声明,若干头文件的声明需要用到compiler hacking,自己复现不好写。
  • -fno-builtin:-ffreestanding暗示了这个flag。
  • -fno-stack-protector:目标平台是*-elf时,该选项被默认禁止。

不用cross compiler会带来什么问题

  • 编译命令复杂
  • libgcc默认使用host系统的
  • 自己重写一些不易正确实现的header
  • 可移植性问题
  • 编译用户态程序困难