构建 EOS

又到了哄编译器开心的时候了.

有了之前的 Makefile 基础, 相信你也可以很快总结出构建 EOS 的思路:

  1. 了解 EOS 构建完成后会生成哪些文件;

  2. 找到生成这些文件的规则, 并且指定生成时依赖的文件;

  3. 使用变量和函数让 Makefile 脚本更为灵活.

那么我们接下来就用这种自顶向下的思路来编写构建 EOS 的 Makefile.

生成的文件

根据 EOS 官方教程, EOS 编译完成之后会生成以下文件:

  • boot.bin: EOS 的引导程序, 将会被写入软盘的引导扇区, 负责执行最初的引导工作;

  • loader.bin: EOS 的内核加载程序, 被 boot.bin 加载后, 负责切换处理器状态并加载内核;

  • kernel.dll: EOS 的内核, 操作系统本体;

  • libkernel.a: EOS 内核的导入库 (import library), 用于给 EOS 用户应用程序提供内核接口信息.

其中, boot.bin 可以由 boot/boot.asm 直接汇编得到; loader.bin 可以由 boot/loader.asm 直接汇编得到; 其余文件需要单独编译为目标文件, 然后使用链接器链接为 DLL 同时生成导入库.

在 EOS 的构建过程中, 所有 .asm 文件均需要使用 nasm 汇编器进行汇编; .c 文件需要使用 MinGW GCC (i686-w64-mingw32-gcc) 进行编译; .o 文件需要使用 MinGW LD (i686-w64-mingw32-ld) 进行链接.

构建规则示例

为了方便调试, 我们需要为编译器和汇编器指定 -g 选项来生成调试信息.

.asm 构建为 .bin

例如将 boot.asm 构建为 boot.bin:

-l *.lst 表示生成列表文件, 其中包含了生成的二进制与汇编源文件的对应关系.

.asm 构建为 .o

例如将 cpu.asm 构建为 cpu.o:

-f win32 表示指定输出的目标格式为 win32.

.c 构建为 .o

例如将 start.c 构建为 start.o:

其中:

  • -c: 仅编译到目标文件;

  • -m32, ..., -ffreestanding: 自行 RTFM;

  • -D_KERNEL_, ...: 预定义宏, 相当于在源码中 #define _KERNEL_, 目的是控制源码的表达;

  • -Isrc/inc, ..., -Isrc/mm/i386: 设置头文件搜索目录, 告诉编译器到这些目录中寻找头文件, 因为 EOS 的头文件 (*.h) 只出现在了这些地方.

.o 构建为 .dll, 同时生成导入库:

其中:

  • -nostdlib: 不使用标准库;

  • -shared: 生成 shared library;

  • --image-base 0x80010000: EOS 内核将会被 loader.bin 加载到虚地址 0x80010000 处, 所以此处指定 DLL 映像的基地址为 0x80010000. 详情请参考官方教程并 RTFSC;

  • -e _KiSystemStartup: 指定 DLL 入口点为 _KiSystemStartup, 即 EOS 内核的初始化函数 (位于 ke/start.c);

  • --out-implib libkernel.a: 生成导入库 libkernel.a.

编写 Makefile

可以得到编译 EOS 内核的 Makefile 如下:

在此之前, 你能尝试自己完成这个 Makefile 脚本吗?

在你理解这个 Makefile 之后, 你可以思考一下这个脚本和上一节出现的那个 Makefile 之间, 在 C 语言文件的构建过程中有什么差异? 这会带来什么问题?

事实上, 这个 Makefile 没有考虑 C 源文件和头文件之间的依赖关系. 所以你也看到了, 作者并不是全能的 (其实是懒), 不如你来出个主意改进一下这个 Makefile, 这样下一次的 OS lab 教程中, 这部分可能就是你写的了.

将其放入 eos 目录中:

尝试构建 EOS 内核:

可以看到 build 目录中已经生成了我们需要的四个文件.

Last updated

Was this helpful?