GNU 程序集引导加载程序无法引导

GNU assembly boot loader won't boot

我一直在学习以下教程:

http://intermezzos.github.io/book/multiboot-headers.html

不幸的是,它使用 NASM 而不是 GNU 汇编器,因为我通常使用 GNU 工具链,所以我宁愿使用它。本教程包含以下简单的 hello world 程序:

section .multiboot_header
header_start:
    dd 0xe85250d6                ; magic number
    dd 0                         ; protected mode code
    dd header_end - header_start ; header length

    ; checksum
    dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))

    ; required end tag
    dw 0    ; type
    dw 0    ; flags
    dd 8    ; size
header_end:

它提供多重引导 header 以及以下内容:

global start
section .text
bits 32
start:
    mov word [0xb8000], 0x0248 ; H
    mov word [0xb8002], 0x0265 ; e
    mov word [0xb8004], 0x026c ; l
    mov word [0xb8006], 0x026c ; l
    mov word [0xb8008], 0x026f ; o
    mov word [0xb800a], 0x022c ; ,
    mov word [0xb800c], 0x0220 ;
    mov word [0xb800e], 0x0277 ; w
    mov word [0xb8010], 0x026f ; o
    mov word [0xb8012], 0x0272 ; r
    mov word [0xb8014], 0x026c ; l
    mov word [0xb8016], 0x0264 ; d
    mov word [0xb8018], 0x0221 ; !
    hlt

这些文件与以下 linker.ld 文件链接在一起:

ENTRY(start)

SECTIONS {
    . = 1M;

    .boot :
    {
        /* ensure that the multiboot header is at the beginning */
        *(.multiboot_header)
    }

    .text :
    {
        *(.text)
    }
}

编译和运行所有这些都可以通过以下方式完成:

nasm -f elf64 boot_nasm.asm
nasm -f elf64 multiboot_header_nasm.asm
ld --nmagic --output=kernel.bin --script=linker.ld multiboot_header_nasm.o boot_nasm.o

查看教程如何使用内核制作 iso 映像以及如何使用 qemu 启动。现在我已经将源代码移植如下以使用 GNU 汇编程序:

    .section .multiboot_header
header_start:
    .long 0xe85250d6             # magic number
    .long 0                      # protected mode code
    .long header_end - header_start

    # checksum
    .long 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))

    # required end tag
    .word 0 # type
    .word 0 # flags
    .long 8 # size
header_end:

    .text
    .global start
    .code32
start:
    movw [=15=]x0248, (0xb8000)      # H
    movw [=15=]x0265, (0xb8002)      # e
    movw [=15=]x026c, (0xb8004)      # l
    movw [=15=]x026c, (0xb8006)      # l
    movw [=15=]x026f, (0xb8008)      # o
    movw [=15=]x022c, (0xb800a)      # ,
    movw [=15=]x0220, (0xb800c)      #
    movw [=15=]x0277, (0xb800e)      # w
    movw [=15=]x026f, (0xb8010)      # o
    movw [=15=]x0272, (0xb8012)      # r
    movw [=15=]x026c, (0xb8014)      # l
    movw [=15=]x0264, (0xb8016)      # d
    movw [=15=]x0221, (0xb8018)      # !
    hlt

我通过以下方式将它们编译并链接在一起:

as boot.S -o boot.o
as multiboot_header.S -o multiboot_header.o
ld --nmagic --output=kernel.bin --script=linker.ld multiboot_header.o boot.o

objdump 表明两种情况输出的 kernel.bin 在每个段中的代码方面是相同的。唯一的区别是段所在的偏移量略有不同。主要区别在于 nasm 版本引导GNU 汇编程序版本不引导

GNU汇编版本给我error: no multiboot header found.

这是两个创建的二进制文件的 objdump 输出:

 % objdump -D -s kernel_nasm.bin 

kernel_nasm.bin:     file format elf64-x86-64

Contents of section .boot:
 100000 d65052e8 00000000 18000000 12afad17  .PR.............
 100010 00000000 08000000                    ........        
Contents of section .text:
 100020 66c70500 800b0048 0266c705 02800b00  f......H.f......
 100030 650266c7 0504800b 006c0266 c7050680  e.f......l.f....
 100040 0b006c02 66c70508 800b006f 0266c705  ..l.f......o.f..
 100050 0a800b00 2c0266c7 050c800b 00200266  ....,.f...... .f
 100060 c7050e80 0b007702 66c70510 800b006f  ......w.f......o
 100070 0266c705 12800b00 720266c7 0514800b  .f......r.f.....
 100080 006c0266 c7051680 0b006402 66c70518  .l.f......d.f...
 100090 800b0021 02f4                        ...!..          

Disassembly of section .boot:

0000000000100000 <header_start>:
  100000:   d6                      (bad)  
  100001:   50                      push   %rax
  100002:   52                      push   %rdx
  100003:   e8 00 00 00 00          callq  100008 <header_start+0x8>
  100008:   18 00                   sbb    %al,(%rax)
  10000a:   00 00                   add    %al,(%rax)
  10000c:   12 af ad 17 00 00       adc    0x17ad(%rdi),%ch
  100012:   00 00                   add    %al,(%rax)
  100014:   08 00                   or     %al,(%rax)
    ...

Disassembly of section .text:

0000000000100020 <start>:
  100020:   66 c7 05 00 80 0b 00    movw   [=17=]x248,0xb8000(%rip)        # 1b8029 <start+0xb8009>
  100027:   48 02 
  100029:   66 c7 05 02 80 0b 00    movw   [=17=]x265,0xb8002(%rip)        # 1b8034 <start+0xb8014>
  100030:   65 02 
  100032:   66 c7 05 04 80 0b 00    movw   [=17=]x26c,0xb8004(%rip)        # 1b803f <start+0xb801f>
  100039:   6c 02 
  10003b:   66 c7 05 06 80 0b 00    movw   [=17=]x26c,0xb8006(%rip)        # 1b804a <start+0xb802a>
  100042:   6c 02 
  100044:   66 c7 05 08 80 0b 00    movw   [=17=]x26f,0xb8008(%rip)        # 1b8055 <start+0xb8035>
  10004b:   6f 02 
  10004d:   66 c7 05 0a 80 0b 00    movw   [=17=]x22c,0xb800a(%rip)        # 1b8060 <start+0xb8040>
  100054:   2c 02 
  100056:   66 c7 05 0c 80 0b 00    movw   [=17=]x220,0xb800c(%rip)        # 1b806b <start+0xb804b>
  10005d:   20 02 
  10005f:   66 c7 05 0e 80 0b 00    movw   [=17=]x277,0xb800e(%rip)        # 1b8076 <start+0xb8056>
  100066:   77 02 
  100068:   66 c7 05 10 80 0b 00    movw   [=17=]x26f,0xb8010(%rip)        # 1b8081 <start+0xb8061>
  10006f:   6f 02 
  100071:   66 c7 05 12 80 0b 00    movw   [=17=]x272,0xb8012(%rip)        # 1b808c <start+0xb806c>
  100078:   72 02 
  10007a:   66 c7 05 14 80 0b 00    movw   [=17=]x26c,0xb8014(%rip)        # 1b8097 <start+0xb8077>
  100081:   6c 02 
  100083:   66 c7 05 16 80 0b 00    movw   [=17=]x264,0xb8016(%rip)        # 1b80a2 <start+0xb8082>
  10008a:   64 02 
  10008c:   66 c7 05 18 80 0b 00    movw   [=17=]x221,0xb8018(%rip)        # 1b80ad <start+0xb808d>
  100093:   21 02 
  100095:   f4                      hlt    

这是使用 GNU 汇编程序创建的版本:

 % objdump -D -s kernel.bin     

kernel.bin:     file format elf64-x86-64

Contents of section .boot:
 100000 d65052e8 00000000 18000000 12afad17  .PR.............
 100010 00000000 08000000                    ........        
Contents of section .text:
 100000 66c70500 800b0048 0266c705 02800b00  f......H.f......
 100010 650266c7 0504800b 006c0266 c7050680  e.f......l.f....
 100020 0b006c02 66c70508 800b006f 0266c705  ..l.f......o.f..
 100030 0a800b00 2c0266c7 050c800b 00200266  ....,.f...... .f
 100040 c7050e80 0b007702 66c70510 800b006f  ......w.f......o
 100050 0266c705 12800b00 720266c7 0514800b  .f......r.f.....
 100060 006c0266 c7051680 0b006402 66c70518  .l.f......d.f...
 100070 800b0021 02f4                        ...!..          

Disassembly of section .boot:

0000000000100000 <header_start>:
  100000:   d6                      (bad)  
  100001:   50                      push   %rax
  100002:   52                      push   %rdx
  100003:   e8 00 00 00 00          callq  100008 <header_start+0x8>
  100008:   18 00                   sbb    %al,(%rax)
  10000a:   00 00                   add    %al,(%rax)
  10000c:   12 af ad 17 00 00       adc    0x17ad(%rdi),%ch
  100012:   00 00                   add    %al,(%rax)
  100014:   08 00                   or     %al,(%rax)
    ...

Disassembly of section .text:

0000000000100000 <start>:
  100000:   66 c7 05 00 80 0b 00    movw   [=18=]x248,0xb8000(%rip)        # 1b8009 <header_end+0xb7ff1>
  100007:   48 02 
  100009:   66 c7 05 02 80 0b 00    movw   [=18=]x265,0xb8002(%rip)        # 1b8014 <header_end+0xb7ffc>
  100010:   65 02 
  100012:   66 c7 05 04 80 0b 00    movw   [=18=]x26c,0xb8004(%rip)        # 1b801f <header_end+0xb8007>
  100019:   6c 02 
  10001b:   66 c7 05 06 80 0b 00    movw   [=18=]x26c,0xb8006(%rip)        # 1b802a <header_end+0xb8012>
  100022:   6c 02 
  100024:   66 c7 05 08 80 0b 00    movw   [=18=]x26f,0xb8008(%rip)        # 1b8035 <header_end+0xb801d>
  10002b:   6f 02 
  10002d:   66 c7 05 0a 80 0b 00    movw   [=18=]x22c,0xb800a(%rip)        # 1b8040 <header_end+0xb8028>
  100034:   2c 02 
  100036:   66 c7 05 0c 80 0b 00    movw   [=18=]x220,0xb800c(%rip)        # 1b804b <header_end+0xb8033>
  10003d:   20 02 
  10003f:   66 c7 05 0e 80 0b 00    movw   [=18=]x277,0xb800e(%rip)        # 1b8056 <header_end+0xb803e>
  100046:   77 02 
  100048:   66 c7 05 10 80 0b 00    movw   [=18=]x26f,0xb8010(%rip)        # 1b8061 <header_end+0xb8049>
  10004f:   6f 02 
  100051:   66 c7 05 12 80 0b 00    movw   [=18=]x272,0xb8012(%rip)        # 1b806c <header_end+0xb8054>
  100058:   72 02 
  10005a:   66 c7 05 14 80 0b 00    movw   [=18=]x26c,0xb8014(%rip)        # 1b8077 <header_end+0xb805f>
  100061:   6c 02 
  100063:   66 c7 05 16 80 0b 00    movw   [=18=]x264,0xb8016(%rip)        # 1b8082 <header_end+0xb806a>
  10006a:   64 02 
  10006c:   66 c7 05 18 80 0b 00    movw   [=18=]x221,0xb8018(%rip)        # 1b808d <header_end+0xb8075>
  100073:   21 02 
  100075:   f4                      hlt    

现在我正在查看它,看起来 GNU 汇编程序版本有一个重叠的 .boot 和 .text 段,所以 grub 在加载文件时可能会用 .text 的数据覆盖 .boot 部分部分。有人知道如何解决这个问题吗?

多重启动规范说:

The Multiboot header must be contained completely within the first 8192 bytes of the OS image, and must be longword (32-bit) aligned.

objdump 给我们:

Idx Name              Size      File off  Algn
  3 .multiboot_header 00000018  00000040  2**0 CONTENTS, READONLY

注意 Algn=2**0.

解决方法:指定对齐方式:

.section .multiboot_header
.balign 4
header_start:

nasm 版本也应该这样做,由于文件布局,它在那里工作只是偶然的。

除了Jester 指出的对齐问题外,我认为链接描述文件是可疑的。它将两个不同的输入部分放入两个不同的输出部分,这可能不是您想要的,并在某种程度上解释了您通过 objdump 看到的差异。改为尝试以下操作:

ENTRY(start)

SECTIONS {
    . = 1M;

    .text :
    {
        /* ensure that the multiboot header is at the beginning */
        *(.multiboot_header)
        *(.text)
    }
}

或者,强制gas使“.multiboot_header”成为multiboot_header.s中的可分配部分:

.section .multiboot_header, "a"