如何用C语言编写linux启动代码?

我是学习OS开发的新手。 从我读过的书中,它说启动加载器会将第一个MBR复制到0x7c00,并从实模式开始。

并且,示例从16位汇编代码开始。 但是,当我查看今天的linux内核时, arch / x86 / boot有’header.S’和’boot.h’,但实际代码是在main.c中实现的。

这似乎是“不编写汇编”有用的。 但是,这是如何在Linux中专门完成的? 我可以粗略地想象可能有特殊的gcc选项和链接策略,但我看不到细节。

我更多地将这个问题作为XY问题阅读。 在我看来,问题更多的是你是否可以在C中为自己的OS开发编写一个bootloader(启动代码)。 简单的答案是肯定的 ,但不推荐。 现代Linux内核可能不是创建用C编写的引导加载程序的最佳信息来源,除非您了解它们的代码在做什么。

如果使用GCC ,则对生成的代码的操作有限制。 在较新版本的GCC中,有一个-m16选项以这种方式记录:

-m16选项与-m32相同,除了它在汇编输出的开头输出".code16gcc"汇编指令,以便二进制可以在16位模式下运行。

这有点欺骗性。 尽管代码可以在16位实模式下运行,但后端生成的代码使用386地址和操作数前缀来使通常32位代码在16位实模式下执行。 这意味着GCC生成的代码不能在386之前的处理器上使用(如8086/80186/80286等)。 如果您想要一个可以在最广泛的硬件arrays上运行的引导加载程序,这可能是一个问题。 如果您不关心386之前的系统,那么GCC将会起作用。

使用GCC的 Bootloader代码有另一个缺点。 添加到许多指令的地址和操作数前缀加起来,可以使引导加载程序膨胀。 引导加载程序的第一阶段通常在空间上受到很大限制,因此这可能会成为一个问题。

您将需要具有与硬件交互的函数的内联汇编语言或汇编语言对象。 您无法在引导加载程序代码中访问Linux C库(printf等)。 例如,如果要写入video显示器,则必须自行编写该function,直接写入video内存或通过BIOS中断。

要将它完全绑定并将内容放在可用作MBR的二进制文件中,您可能需要一个特制的链接描述文件。 在大多数项目中,这些链接描述文件具有.ld扩展名。 这推动了将所有目标文件以与传统BIOS引导过程兼容的方式(在0x07c00以实模式运行的代码)将它们放在一起的过程。

这样做有很多陷阱,我建议不要这样做 。 如果您打算编写32位或64位内核,那么我建议不要编写自己的引导加载程序并使用GRUB之类的现有引导加载程序。 在20世纪90年代的Linux版本中,它有自己的bootloader,可以从软盘执行。 现代Linux依赖第三方引导程序来完成大部分工作。 特别是它支持符合Multiboot规范的引导加载程序

互联网上有许多使用GRUB作为引导加载程序的教程。 OS Dev Wiki是一个非常宝贵的资源。 他们有一个Bare Bones教程,它使用原始的Multiboot规范(由GRUB支持)来启动基本内核。 可以使用最少的汇编语言代码轻松开发Mulitboot规范。 多引导兼容引导加载程序将自动将CPU置于保护模式,启用A20线,可用于获取内存映射,并且可以告诉您在引导时将您置于特定的video模式。


去年#Osdev聊天的人询问是否写了一个位于完全用GCC和内联汇编开发的软盘(或磁盘映像)的前2个扇区中的2阶段引导加载程序。 我不推荐这个,因为它相当复杂,内联汇编很难做到。 编写看似有效但不正确的坏内联汇编非常容易 。

我提供了一些使用链接描述文件的示例代码 , C使用内联汇编来处理BIOS中断以从磁盘读取并写入video显示。 如果有任何代码应该是一个例子,为什么做你要求的事情并不重要。