linux引导代码如何用C编写? [英] How can linux boot code be written in C?

查看:92
本文介绍了linux引导代码如何用C编写?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是学习OS开发的新手.从我读过的书中可以看出,引导加载程序会将第一个MBR复制到0x7c00,然后以实模式从那里开始.

I'm a newbie to learning OS development. From the book I read, it said that boot loader will copy first MBR into 0x7c00, and starts from there in real mode.

并且,示例以16位汇编代码开头. 但是,当我查看当今的Linux内核时, arch/x86/boot 具有"header.S"和"boot.h",但是实际代码在main.c中实现.

And, example starts with 16 bit assembly code. But, when I looked at today's linux kernel, arch/x86/boot has 'header.S' and 'boot.h', but actual code is implemented in main.c.

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

This seems to be useful by "not writing assembly." But, how is this done specifically in Linux? I can roughly imagine that there might be special gcc options and link strategy, but I can't see the detail.

推荐答案

作为X-Y问题,我正在阅读更多此问题.在我看来,问题更多是关于您是否可以为自己的OS开发用 C 编写引导加载程序(引导代码).简单的答案是 YES ,但不建议这样做.除非您了解它们的代码功能,否则现代Linux内核可能不是创建用 C 编写的引导程序的最佳信息来源.

I'm reading this question more as an X-Y problem. It seems to me the question is more about whether you can write a bootloader (boot code) in C for your own OS development. The simple answer is YES, but not recommended. Modern Linux kernels are probably not the best source of information for creating bootloaders written in C unless you have an understanding of what their code is doing.

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

If using GCC there are restrictions on what you can do with the generated code. In newer versions of GCC there is an -m16 option that is documented this way:

-m16 选项与-m32相同,区别在于它在汇编输出的开头输出".code16gcc"汇编指令,以便二进制文件可以以16位运行模式.

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 将起作用.

This is a bit deceptive. Although the code can run in 16-bit real mode, the code generated by the back end uses 386 address and operand prefixes to make normally 32-bit code execute in 16-bit real mode. This means the code generated by GCC can't be used on processors earlier than the 386 (like the 8086/80186/80286 etc). This can be a problem if you want a bootloader that can run on the widest array of hardware. If you don't care about pre-386 systems then GCC will work.

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

Bootloader code that uses GCC has another downside. The address and operand prefixes that get get added to many instructions add up and can make a bootloader bloated. The first stage of a bootloader is usually very constrained in space so this could potentially become a problem.

您将需要具有功能的嵌入式汇编或汇编语言对象,以与硬件进行交互.您无权访问Bootloader代码中的Linux C 库(printf等).例如,如果要写入视频显示器,则必须自己编写代码以直接写入视频内存或通过BIOS中断来编写该功能.

You will need inline assembly or assembly language objects with functions to interact with the hardware. You don't have access to the Linux C library (printf etc) in bootloader code. For example if you want to write to the video display you have to code that functionality yourself either writing directly to video memory or through BIOS interrupts.

要将其完全捆绑在一起并将其放置在可用作MBR的二进制文件中,您可能需要特制的链接描述文件.在大多数项目中,这些链接程序脚本均具有.ld扩展名.这样可以驱动将所有目标文件放到与旧版BIOS引导程序兼容的方式(代码以实模式运行于0x07c00)的过程中.

To tie it altogether and place things in the binary file usable as an MBR you will likely need a specially crafted linker script. In most projects these linker scripts have an .ld extension. This drives the process of taking all the object files putting them together in a fashion that is compatible with the legacy BIOS boot process (code that runs in real mode at 0x07c00).

这样做有很多陷阱,我建议您反对.如果您打算编写32位或64位内核,那么我建议您不要编写自己的引导程序,而要使用现有的 GRUB 引导程序.在1990年代的Linux版本中,它具有自己的引导加载程序,可以通过软盘执行该引导加载程序.现代Linux现在依靠第三方引导程序来完成大部分工作.特别是,它支持符合 Multiboot规范

There are so many pitfalls in doing this that I recommend against it. If you are intending to write a 32-bit or 64-bit kernel then I'd suggest not writing your own bootloader and use an existing one like GRUB. In the versions of Linux from the 1990s it had its own bootloader that could be executed from floppy. Modern Linux relies on third party bootloaders to do most of that work now. In particular it supports bootloaders that conform to the Multiboot specification

互联网上有许多教程使用 GRUB 作为引导程序. OS Dev Wiki 是宝贵的资源.他们有一个裸骨教程,该教程使用原始的Multiboot规范(由GRUB支持)来引导基本的核心.可以很容易地开发Mulitboot规范,以使用最少的汇编语言代码.兼容Multiboot的引导加载程序将自动将CPU置于保护模式,启用A20线路,可用于获取内存映射,并在启动时被告知将您置于特定的视频模式.

There are many tutorials on the internet that use GRUB as a bootloader. OS Dev Wiki is an invaluable resource. They have a Bare Bones tutorial that uses the original Multiboot specification (supported by GRUB) to boot strap a basic kernel. The Mulitboot specification can easily be developed for using a minimal of assembly language code. Multiboot compatible bootloaders will automatically place the CPU in protected mode, enable the A20 line, can be used to get a memory map, and can be told to place you in a specific video mode at boot time.

去年,有人在 #Osdev 聊天中询问有关编写一个位于第一个阶段的两阶段引导程序的问题软盘的2个扇区(或磁盘映像)完全通过 GCC 和内联汇编开发.我不建议这样做,因为它相当复杂,并且内联汇编很难正确实现. 易于编写不良的内联汇编似乎可行,但并不正确.

Last year someone on the #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 that seems to work but isn't correct.

我提供了使用链接器脚本的一些示例代码 ,具有嵌入式汇编的 C 可以与BIOS中断一起从磁盘读取并写入视频显示.如果有什么需要,这段代码可以作为一个示例,说明为什么要完成所要求的工作并非易事.

I have made available some sample code that uses a linker script, C with inline assembly to work with the BIOS interrupts to read from the disk and write to the video display. If anything this code should be an example why it's non-trivial to do what you are asking.

这篇关于linux引导代码如何用C编写?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆