答案1
我欢迎更好的答案,但我的理解是,它是在汇编中手写的内核启动代码(特定于体系结构)(记住,此时我们只有裸机 CPU 和对内存的原始访问;我们不能访问存储在文件系统上的复杂库,因为我们还没有文件管理器 - 这就像问谁创造了大爆炸)。不要将其与引导加载程序(将引导扇区从磁盘加载到 RAM 中)混淆。我自己在之前的回答中也对它们感到困惑。
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
' bootloader ' ' kernel '
' ' ' '
+------+ ' +-----------------------------------+ +------------------------------+ ' ' +-----------------------------+ +---------------------------------------+ '
| BIOS | --> ' | arch/x86/boot/header.S::call main | --> | arch/x86/boot/main.c::main() | ' --> ' | init/main.c::start_kernel() | --> | arch/x86/kernel/setup.c::setup_arch() | '
+------+ ' +-----------------------------------+ +------------------------------+ ' ' +-----------------------------+ +---------------------------------------+ '
' ' ' '
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
(编辑:这是 Minix,我最初错误地将其放入)
+------+ +--------------------+ +------------------+ +------------------------+
| BIOS | --> | Bootloader (mbr.S) | --> | startup (head.S) | --> | kernel/main.c::kmain() |
+------+ +--------------------+ +------------------+ +------------------------+
在 head.S 的末尾你会看到这条线
call _C_LABEL(kmain)
这是内核的入口点:
kernel/main.c
我相信head.S
在编译时附加到内核映像的顶部。 BIOS 知道执行这段代码,因为它位于最开始,并且是 RAM 磁盘的根文件系统。
至于为什么会有压缩和未压缩的部分,我认为是因为内核映像的架构特定的汇编部分,没有程序员足够熟练地进行压缩。一旦我们可以跳转到kmain
用 C 编写的例程(但编译成汇编),我们就可以访问解压缩例程,这使得内核占用空间显着减小。
http://duartes.org/gustavo/blog/post/kernel-boot-process/
使用汇编的入口点
我们喜欢用 C 语言编写所有内容,但我们无法避免一点汇编。我们将用 x86 汇编语言编写一个小文件,作为内核的起点。我们的汇编文件要做的就是调用我们用 C 编写的外部函数,然后停止程序流程。
我们如何确保该汇编代码将作为内核的起点?
我们将使用链接器脚本来链接目标文件以生成最终的内核可执行文件。 (稍后详细解释)在此链接描述文件中,我们将明确指定我们希望将二进制文件加载到地址 0x100000。正如我之前所说,这个地址是内核预期所在的位置。因此,引导加载程序将负责触发内核的入口点。
http://arjunsreedharan.org/post/82710718100/kernel-101-lets-write-a-kernel