main()只是出于熟悉和美观的原因选择了这个名字;没有 C 运行时调用它,就像main()来自用户空间程序一样。甚至有一条评论也说明了这一点init/main.c:
void main(void) /* This really IS void, no error here. */
该main()函数从以下位置调用boot/head.s:
after_page_tables:
pushl $0 # These are the parameters to main :-)
pushl $0
pushl $0
pushl $L6 # return address for main, if it decides to.
pushl $_main
jmp setup_paging
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens
当 Linux 处理硬盘时,引导过程仍然非常简单。它非常简单,以至于可以创建诸如“loadlin”之类的工具,这是一个简单的 DOS 程序,可以加载 Linux 内核并引导到其中,模拟 BIOS 加载程序。这样就可以创建一个 DOS config.sys 菜单来引导 DOS 或 Linux;双引导的早期形式。
该main函数是C语言的一个特性。它如何准确地转换为 CPU “从这里开始”的计算机指令基本上是编译器实现的细节。在裸机上,您通常可以简单地依赖硬件在首次启动时从特定内存地址开始执行。Linux 的早期版本依赖于 a. 简单的 x86 引导加载程序;今天,该角色通常由 Grub 处理。反过来,这种行为取决于 BIOS 固件约定,但实际上,在每个级别上,您都有一个计算机架构,其中包含如何启动程序的约定。
main()
只是出于熟悉和美观的原因选择了这个名字;没有 C 运行时调用它,就像main()
来自用户空间程序一样。甚至有一条评论也说明了这一点init/main.c
:该
main()
函数从以下位置调用boot/head.s
:注意 的地址是如何
main
被压入堆栈的,并且setup_paging
是用 调用的jmp
,而不是用调用的call
,这意味着ret
在它的末尾将继续从 开头main()
。Linux 内核,尤其是 0.11 天的内核,是由硬件 BIOS 直接加载的。
基本上,BIOS 会查看(软盘的)引导扇区或硬盘的主引导记录,然后加载该扇区。使用硬盘,MBR 然后加载“主分区”引导扇区。
这个加载的引导扇区有足够的信息来了解如何将内核加载到内存中,然后运行它。
对于旧的 0.11 磁盘,它实际上是一种软盘引导解决方案,内核在一个磁盘上,root 在另一个磁盘上,因此引导系统非常简单。
当 Linux 处理硬盘时,引导过程仍然非常简单。它非常简单,以至于可以创建诸如“loadlin”之类的工具,这是一个简单的 DOS 程序,可以加载 Linux 内核并引导到其中,模拟 BIOS 加载程序。这样就可以创建一个 DOS config.sys 菜单来引导 DOS 或 Linux;双引导的早期形式。
但从本质上讲,Linux 内核是从“裸机”加载并接管机器的。
该
main
函数是C语言的一个特性。它如何准确地转换为 CPU “从这里开始”的计算机指令基本上是编译器实现的细节。在裸机上,您通常可以简单地依赖硬件在首次启动时从特定内存地址开始执行。Linux 的早期版本依赖于 a. 简单的 x86 引导加载程序;今天,该角色通常由 Grub 处理。反过来,这种行为取决于 BIOS 固件约定,但实际上,在每个级别上,您都有一个计算机架构,其中包含如何启动程序的约定。