linux引导代码怎么用C写的?
How can linux boot code be written in C?
我是学习 OS 开发的新手。我看过的书上说boot loader会把第一个MBR复制到0x7c00,然后从那里开始实模式。
并且,示例以 16 位汇编代码开头。
但是,当我查看今天的 linux 内核时, arch/x86/boot 有 'header.S' 和 'boot.h',但实际代码是在 main.c.
中实现的
这似乎对"not writing assembly."有用
但是,这在 Linux 中具体是如何完成的?
我可以粗略想象可能会有特殊的 gcc
选项和 link 策略,但我看不到细节。
我更多地将此问题视为 X-Y 问题。在我看来,问题更多的是关于您是否可以在 C 中为您自己的 OS 开发编写引导加载程序(引导代码)。简单的答案是 YES,但不推荐。现代 Linux 内核可能不是创建用 C 编写的引导加载程序的最佳信息来源,除非您了解它们的代码在做什么。
如果使用 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 的引导加载程序代码还有另一个缺点。添加到许多指令中的地址和操作数前缀加起来会使引导加载程序变得臃肿。引导加载程序的第一阶段通常在 space 中非常受限,因此这可能会成为一个问题。
您将需要具有与硬件交互功能的内联汇编或汇编语言对象。您无权访问引导加载程序代码中的 Linux C 库(printf 等)。例如,如果你想写入视频显示,你必须自己编写该功能的代码,要么直接写入视频内存,要么通过 BIOS 中断。
要将其完全绑定并将内容放入可用作 MBR 的二进制文件中,您可能需要一个特制的链接描述文件。在大多数项目中,这些链接描述文件都有一个 .ld
扩展名。这推动了获取所有目标文件的过程,将它们以与遗留 BIOS 引导过程兼容的方式组合在一起(代码 运行s 在 0x07c00 的实模式中)。
这样做有很多陷阱,我建议不要这样做。如果您打算编写 32 位或 64 位内核,那么我建议您不要编写自己的引导加载程序,而是使用现有的 GRUB。在 1990 年代的 Linux 版本中,它有自己的引导加载程序,可以从软盘执行。 Modern Linux 现在依靠第三方引导加载程序来完成大部分工作。特别是它支持符合 Multiboot specification
的引导加载程序
互联网上有很多使用 GRUB 作为引导加载程序的教程。 OS Dev Wiki is an invaluable resource. They have a Bare Bones 使用原始多重引导规范(受 GRUB 支持)引导基本内核的教程。可以使用最少的汇编语言代码轻松开发 Mulitboot 规范。 Multiboot 兼容的引导加载程序会自动将 CPU 置于保护模式,启用 A20 线,可用于获取内存映射,并可被告知在引导时将您置于特定的视频模式。
去年 #Osdev chat asked about writing a 2 stage bootloader located in the first 2 sectors of a floppy disk (or disk image) developed entirely in GCC and inline assembly. I don't recommend this as it is rather complex and inline assembly is very hard to get right. It is very easy to write bad inline assembly 上有人似乎有效但不正确。
我已经提供了 some sample code,它使用一个链接器脚本,C 和内联汇编来处理 BIOS 中断以从磁盘读取并写入视频显示。如果有的话,这段代码应该是一个例子,为什么做你所要求的事情是不平凡的。
我是学习 OS 开发的新手。我看过的书上说boot loader会把第一个MBR复制到0x7c00,然后从那里开始实模式。
并且,示例以 16 位汇编代码开头。 但是,当我查看今天的 linux 内核时, arch/x86/boot 有 'header.S' 和 'boot.h',但实际代码是在 main.c.
中实现的这似乎对"not writing assembly."有用
但是,这在 Linux 中具体是如何完成的?
我可以粗略想象可能会有特殊的 gcc
选项和 link 策略,但我看不到细节。
我更多地将此问题视为 X-Y 问题。在我看来,问题更多的是关于您是否可以在 C 中为您自己的 OS 开发编写引导加载程序(引导代码)。简单的答案是 YES,但不推荐。现代 Linux 内核可能不是创建用 C 编写的引导加载程序的最佳信息来源,除非您了解它们的代码在做什么。
如果使用 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 的引导加载程序代码还有另一个缺点。添加到许多指令中的地址和操作数前缀加起来会使引导加载程序变得臃肿。引导加载程序的第一阶段通常在 space 中非常受限,因此这可能会成为一个问题。
您将需要具有与硬件交互功能的内联汇编或汇编语言对象。您无权访问引导加载程序代码中的 Linux C 库(printf 等)。例如,如果你想写入视频显示,你必须自己编写该功能的代码,要么直接写入视频内存,要么通过 BIOS 中断。
要将其完全绑定并将内容放入可用作 MBR 的二进制文件中,您可能需要一个特制的链接描述文件。在大多数项目中,这些链接描述文件都有一个 .ld
扩展名。这推动了获取所有目标文件的过程,将它们以与遗留 BIOS 引导过程兼容的方式组合在一起(代码 运行s 在 0x07c00 的实模式中)。
这样做有很多陷阱,我建议不要这样做。如果您打算编写 32 位或 64 位内核,那么我建议您不要编写自己的引导加载程序,而是使用现有的 GRUB。在 1990 年代的 Linux 版本中,它有自己的引导加载程序,可以从软盘执行。 Modern Linux 现在依靠第三方引导加载程序来完成大部分工作。特别是它支持符合 Multiboot specification
的引导加载程序互联网上有很多使用 GRUB 作为引导加载程序的教程。 OS Dev Wiki is an invaluable resource. They have a Bare Bones 使用原始多重引导规范(受 GRUB 支持)引导基本内核的教程。可以使用最少的汇编语言代码轻松开发 Mulitboot 规范。 Multiboot 兼容的引导加载程序会自动将 CPU 置于保护模式,启用 A20 线,可用于获取内存映射,并可被告知在引导时将您置于特定的视频模式。
去年 #Osdev chat asked about writing a 2 stage bootloader located in the first 2 sectors of a floppy disk (or disk image) developed entirely in GCC and inline assembly. I don't recommend this as it is rather complex and inline assembly is very hard to get right. It is very easy to write bad inline assembly 上有人似乎有效但不正确。
我已经提供了 some sample code,它使用一个链接器脚本,C 和内联汇编来处理 BIOS 中断以从磁盘读取并写入视频显示。如果有的话,这段代码应该是一个例子,为什么做你所要求的事情是不平凡的。