本文介绍了创建一个简单的多重内核加载GRUB2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图按照指示在这里建立一个简单的OS内核:

除,而不是从软盘启动,我想创建一个基于GRUB的ISO映像和引导模拟器多重引导的CD。我已经添加了以下在该页面中列出,对于多重包头中的源:

  MBALIGN EQU 1 LT;℃的;对齐页面边界上加载的模块
meminfo的EQU 1 LT;< 1;提供内存映射
FLAGS EQU MBALIGN | meminfo中;这是多引导标志字段
MAGIC EQU 0x1BADB002; 幻数让引导程序找到头
CHECKSUM EQU - (MAGIC +标志);以上校验,以证明我们是多重
部分.multiboot
4对齐
    DD MAGIC
    DD FLAGS
    DD校验

和我做下面创建映像:

  NASM -felf32 -o init.bin init.s
CP init.bin目标的/ boot / init.bin
GRUB2-mkrescue -o init.iso目标/

然后我跑QEMU来引导它:

 的qemu-系统x86_64的-cdrom ./init.iso

从启动菜单中选择myos'后,我得到的错误

 错误:无效的拱依赖ELF魔

这是什么意思,以及如何解决?我试着用ELF格式搞乱,但只有 -felf32 似乎工作...


解决方案

GRUB支持的 ELF32 的平坦二进制文件。你的头,虽然含蓄地说,你是提供的 ELF 的二进制文件。

使用扁平二进制多重引导

如果您想告诉您正在使用一台二进制必须设置多重引导装载程序(GRUB)的第16位的为1:

  MULTIBOOT_AOUT_KLUDGE EQU 1 LT;< 16
                              ; FLAGS [16]指示GRUB我们不
                              ; ELF可执行文件和田野
                              ;头地址,加载地址,负载端地址,
                              ; BSS结束地址,以及入口地址将是
                              ;在我们的多重引导头可用

这是不是只是指定这个标志一样简单。你必须提供完整的多重引导头,提供了多重引导加载程序的信息,我们的二进制加载到内存中。当使用的 ELF 的格式信息是在 ELF 的标题是precedes我们code所以没有被明确规定。多重引导头在定义很详细。

在使用的 NASM 的有 -f斌要注意的是,我们需要指定我们的code原点是很重要的。多重引导装载程序来载入我们的物理地址的0x100000 内核。我们必须在我们的汇编文件中指定我们的原点是的0x100000 ,以便适当偏移等将在我们的最终平二值图像获取生成。

这是剥离,从我自己的项目之一,它提供了一个简单的头修饰的例子。到主程序的呼叫建立比如上例中的C调用,但你不必这样做的。通常我调入,是以堆栈上的几个参数的函数(使用C调用约定)。

  [BITS 32]
[全球_start]
[ORG的0x100000];如果使用-f本',我们需要指定
                              ;原点为我们code。与ORG指令
                              ;多重装载机加载在我们的身体
                              ;地址0x100000处MULTIBOOT_AOUT_KLUDGE EQU 1 LT;< 16
                              ; FLAGS [16]指示GRUB我们不
                              ; ELF可执行文件和田野
                              ;头地址,加载地址,负载端地址;
                              ; BSS结束地址和入口地址将可用
                              ;在多重引导头
MULTIBOOT_ALIGN EQU 1所述;℃下;对齐页面边界上加载的模块
MULTIBOOT_MEMINFO EQU 1所述;&所述; 1;提供内存映射MULTIBOOT_HEADER_MAGIC EQU 0x1BADB002
                              ;在第一个8K的幻数GRUB搜索
                              ;内核文件GRUB被告知要加载MULTIBOOT_HEADER_FLAGS EQU MULTIBOOT_AOUT_KLUDGE | MULTIBOOT_ALIGN | MULTIBOOT_MEMINFO
CHECKSUM EQU - (MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)KERNEL_STACK EQU 0x00200000;堆栈开始在2MB地址和放大器;向下增长_开始:
        XOR EAX,EAX;清EAX和EBX事件
        XOR EBX,EBX;我们不被GRUB加载。
        JMP multiboot_entry;跃过多重引导头
        调整4;多重引导头必须是32
                                       ;位对齐,以避免错误13
multiboot_header:
        DD MULTIBOOT_HEADER_MAGIC;幻数
        DD MULTIBOOT_HEADER_FLAGS;标志
        DD校验,校验
        DD multiboot_header;头地址
        DD _start code入口点的加载地址
                                       ;在我们的例子_start
        DD 00;负载端地址:没有必要
        DD 00; BSS结束地址:没有必要
        DD multiboot_entry;入口地址GRUB将开始multiboot_entry:
        MOV ESP,KERNEL_STACK;设置堆​​栈
        推0;复位EFLAGS
        POPF        推EAX;第二个参数是神奇的数字
        推EBX;第一个参数多重信息指针
        调用_MAIN;调用_MAIN
        ADD ESP,8;清理8个字节推作为参数        CLI
ENDLOOP:
        HLT
        JMP ENDLOOP_主要:
        RET;没做什么

多重引导装载程序(的 GRUB 的)一般加载在你的文件的第一个8K(是否 ELF 的或扁平二进制),查找多重引导头中的32位边界上。如果的多重引导头标志的位16 的是明确的,它假定您提供的 ELF 的形象。然后它分析的 ELF 的标题检索,它需要你的内核文件加载到内存中的信息。如果的第16位的设置则需要一个完整的多重引导头,使装载机具有信息读取内核到内存,进行初始化,然后调用到你的内核。

您会再组装你的 init.s 来的东西像一个扁平二进制文件:

  NASM -f -o init.bin init.s斌

使用ELF与多重

要在小丑的言论系在你原来的问题,您应该已经能够用的 ELF 的启动,它的工作,但它并没有因为一个小细节。在您的例子,你用它来制作的 init.bin 的:

  NASM -f ELF32 -o init.bin init.s

在使用 -f ELF32 NASM 的产生与目标文件(它们不是可执行的),必须链接( LD 的为例)生成最终的 ELF 的(ELF32)可执行文件。这本来可能的工作,如果你有喜​​欢的东西所做的汇编和链接的过程:

  NASM -f ELF32 init.s -o init.o
LD -Ttext = 0x100000处-melf_i386 -o init.bin init.o

请注意,使用 -f ELF32 时,必须从的 init.s 的删除的 ORG 的指令。在 ORG 的指令只能使用 -f斌时适用。多重引导加载器将在物理地址的0x100000 加载我们,我们必须确保组装和链接code与该原点产生。当使用 -f ELF32 我们指定与 -Ttext =的0x100000 的入口点链接器( LD 的)命令行。另外原点可以在链接脚本进行设置。

使用NASM / LD / objcopy把要生成平二值图像

有可能使用的 NASM / LD / objcopy把的在一起,产生最终的扁平二进制图像,而不是使用 -f斌 NASM 的。如果您的 init.s 的删除的 ORG 的指令,并使用这些命令,应该产生一个平坦二进制的 init.bin 的:

  NASM -f ELF32 init.s -o init.o
LD -Ttext = 0x100000处-melf_i386 -o init.elf init.o
objcopy把-O二进制init.elf init.bin

在此, NASM 的被告知产生的 ELF32 的对象。我们集合 init.s 的成的 ELF 的对象调用的 init.o 的文件。然后我们可以使用连接器( LD 的)来生成的 init.o 的一个 ELF 的可执行文件名为 init.elf 的。我们使用一个名为 objcopy把的剥离特别节目所有的 ELF 的头关,并产生所谓的扁平二进制可执行文件的 init.bin 的。

这是一个很大的不仅仅是使用的 NASM 的使用 -f斌选项生成可执行平更复杂的 init.bin 的。何苦呢?与上面的方法,你可以告诉的 NASM 的生成可以通过的 GDB 的(GNU调试器)被用来调试信息。如果您尝试使用 -g (启用调试)用的 NASM 的使用 -f斌没有调试信息获取生成。您可以通过改变装配顺序这种方式产生的调试信息:

  NASM -g3 -F矮-f ELF32 init.s -o init.o
LD -Ttext = 0x100000处-melf_i386 -o init.elf init.o
objcopy把-O二进制init.elf init.bin

init.o 的将包含调试信息(侏儒的格式),将与的 LD 的成的 init.elf 的(它保留调试信息)。扁平的二进制文件不包含调试信息,因为它们被剥去当您使用的 objcopy把的有 -O二进制。您可以使用的 init.elf 的,如果你启用的 QEMU 的远程调试设备,并使用的 GDB 的调试。在此调试信息的 init.elf 的提供信息,让您单步通过你的code,访问变量和标签的名字调试器,看源汇编code等。

除了生成调试信息,还有另外一个理由使用的 NASM / LD / objcopy把的过程中生成一个内核二进制文件。的 LD 的是多的配置。的 LD 的允许一个人创建连接器脚本,让您更好地调整得到的东西怎么在最终的二进制布局。这可以是更复杂的内核可能包含来自不同的环境(C,汇编等)code的混合物是有用的。对于一个小玩具内核它可能不被需要的,但作为内核生长在复杂性使用链接脚本将变得更加明显。

与QEMU GDB远程调试

如果您使用在previous节中的方法来生成调试的 ELF 的可执行文件中的信息( init.elf 的),你可以启动的 QEMU 的和有它:


  • 加载的 QEMU 的环境,并在启动时停止CPU。从手册页:

  • Make QEMU listen for a GDB remote connection on localhost:1234 . From man page:

Then you just have to launch GDB so that it:

  • Launches GDB with our ELF executable (init.elf) with debug symbols and information
  • Connects to localhost:1234 where QEMU is listening
  • Sets up the debug layout of your choice
  • Sets a break point to stop in our kernel (in this example multiboot_entry)

Here is an example of launching our kernel from the CD-ROM image init.iso, and launching GDB to connect to it:

qemu-system-x86_64 -cdrom ./init.iso -S -s &    
gdb init.elf \
        -ex 'target remote localhost:1234' \
        -ex 'layout src' \
        -ex 'layout regs' \
        -ex 'break multiboot_entry' \
        -ex 'continue'

You should be able to use GDB in much the same way as debugging a normal program. This assumes you will not be debugging a 16-bit program (kernel).

Important Considerations

As Jester points out, when using Multiboot compliant loaders like GRUB, the CPU is in 32-bit protected mode (not 16-bit real mode). Unlike booting right from the BIOS, you won't be able to use 16-bit code including most of the PC-BIOS interrupts. If you need to be in real mode you would have to change back to real mode manually, or create a VM86 task (the latter isn't trivial).

This is an important consideration since some of the code you linked to in MikeOS is 16-bit.

这篇关于创建一个简单的多重内核加载GRUB2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 12:24