并且,示例从16位汇编代码开始.
但是,当我查看今天的linux内核时,arch/x86/boot有’header.S’和’boot.h’,但实际代码是在main.c中实现的.
这似乎是“不编写汇编”有用的.
但是,这是如何在Linux中专门完成的?
我可以粗略地想象可能有特殊的gcc选项和链接策略,但我看不到细节.
解决方法
如果使用GCC,则对生成的代码的操作有限制.在较新版本的GCC中,有一个-m16选项以这种方式记录:
The
-m16
option is the same as -m32,except for that it outputs the".code16gcc"
assembly directive at the beginning of the assembly output so that the binary can run in 16-bit mode.
这有点欺骗性.尽管代码可以在16位实模式下运行,但后端生成的代码使用386地址和操作数前缀来使通常32位代码在16位实模式下执行.这意味着GCC生成的代码不能在386之前的处理器上使用(如8086/80186/80286等).如果您想要一个可以在最广泛的硬件阵列上运行的引导加载程序,这可能是一个问题.如果您不关心386之前的系统,那么GCC将会起作用.
使用GCC的Bootloader代码有另一个缺点.添加到许多指令的地址和操作数前缀加起来,可以使引导加载程序膨胀.引导加载程序的第一阶段通常在空间上受到很大限制,因此这可能会成为一个问题.
您将需要具有与硬件交互的函数的内联汇编语言或汇编语言对象.您无法在引导加载程序代码中访问Linux C库(printf等).例如,如果要写入视频显示器,则必须自行编写该功能,直接写入视频内存或通过BIOS中断.
要将它完全绑定并将内容放在可用作MBR的二进制文件中,您可能需要一个特制的链接描述文件.在大多数项目中,这些链接描述文件具有.ld扩展名.这推动了将所有目标文件以与传统BIOS引导过程兼容的方式(在0x07c00以实模式运行的代码)将它们放在一起的过程.
这样做有很多陷阱,我建议不要这样做.如果您打算编写32位或64位内核,那么我建议不要编写自己的引导加载程序并使用GRUB之类的现有引导加载程序.在20世纪90年代的Linux版本中,它有自己的bootloader,可以从软盘执行.现代Linux依赖第三方引导程序来完成大部分工作.特别是它支持符合Multiboot specification的引导加载程序
互联网上有许多使用GRUB作为引导加载程序的教程. OS Dev Wiki是一个非常宝贵的资源.他们有一个Bare Bones教程,它使用原始的多重引导规范(由GRUB支持)来引导基本内核.可以使用最少的汇编语言代码轻松开发Mulitboot规范.多引导兼容引导加载程序将自动将cpu置于保护模式,启用A20线,可用于获取内存映射,并且可以告诉您在引导时将您置于特定的视频模式.
去年有人在#Osdev聊天时询问是否写了一个2级引导加载程序,它位于完全用GCC和内联汇编开发的软盘(或磁盘映像)的前2个扇区中.我不推荐这个,因为它相当复杂,内联汇编很难做到.这是easy to write bad inline assembly似乎工作但不正确.
我已经提供了some sample code使用链接器脚本,C使用内联汇编来处理BIOS中断以从磁盘读取并写入视频显示.如果有任何代码应该是一个例子,为什么做你要求的事情并不重要.