我遇到了Grub 2(和QEMU的-kernel)无法在内核中检测到Multiboot v1标头的问题。我在.text之前的单独部分中具有标题。

linker.ld

SECTIONS
{
    . = 1M;

    .multiboot ALIGN(4K) :
    {
        *(.multiboot)
    }

    .text ALIGN(4K) :
    {
        *(.text)
    }

    [snip]


boot.s(GNU为语法):

.set MAGIC, 0x1badb002
.set FLAGS, (1<<0 | 1<<1) # align, provide mem map
.set CHECKSUM, -(MAGIC + FLAGS)

.section .multiboot
    .long MAGIC
    .long FLAGS
    .long CHECKSUM

.section .text
    [snip]


我已验证是否按魔术数字指定添加了标头部分:

kernel.bin:     file format elf32-i386

Contents of section .multiboot:
 101000 02b0ad1b 03000000 fb4f52e4           .........OR.
Contents of section .text:
 [snip]


但是Grub 2表示内核没有有效的Multiboot头,并且使用QEMU的-kernel选项会导致:

qemu: fatal: Trying to execute code outside RAM or ROM at 0x000a000


这似乎是BIOS映射范围内的地址,而不是Multiboot应该位于的地址。

我已经将其与Bran's和OSDev(加上我的以前的内核)中的常规代码进行了比较,但我似乎无法弄清楚自己在做什么错。

最佳答案

我的多重引导内核遇到了同样的错误。当.text部分的大小超过大约4k时,我遇到了同样的错误。我的问题的原因是,在链接时,我在ld参数中首先指定了kernel.o,然后指定了loader.o(我基于OSDev Wiki Bare Bones编写了一个Makefile来使我的项目更易于开发)。 Multiboot应该在前4k中查找标头,并且随着我代码的增长,它会将标头推出该区域(因为它位于kernel .text节中的加载程序之前)。您为multiboot标头使用了单独的部分,我不知道这可能是一个好主意,也可能不是一个好主意。我会尝试的事情:


删除.multiboot节,并将其内容放入加载程序的开头,并确保loa​​der.o是链接程序的第一个参数,然后是kernel.o。
使用readelf -a kernel来确保multiboot标头确实在前4k中(也就是说,如果起始位置在0x00100000处,则其偏移量小于0x00101000

07-26 00:39