GNU程序集启动加载程序无法启动

时间:2016-06-23 14:04:57

标签: assembly nasm ld boot gas

我一直在阅读以下教程:

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:

提供多引导头以及以下内容:

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 $0x0248, (0xb8000)      # H
    movw $0x0265, (0xb8002)      # e
    movw $0x026c, (0xb8004)      # l
    movw $0x026c, (0xb8006)      # l
    movw $0x026f, (0xb8008)      # o
    movw $0x022c, (0xb800a)      # ,
    movw $0x0220, (0xb800c)      #
    movw $0x0277, (0xb800e)      # w
    movw $0x026f, (0xb8010)      # o
    movw $0x0272, (0xb8012)      # r
    movw $0x026c, (0xb8014)      # l
    movw $0x0264, (0xb8016)      # d
    movw $0x0221, (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   $0x248,0xb8000(%rip)        # 1b8029 <start+0xb8009>
  100027:   48 02 
  100029:   66 c7 05 02 80 0b 00    movw   $0x265,0xb8002(%rip)        # 1b8034 <start+0xb8014>
  100030:   65 02 
  100032:   66 c7 05 04 80 0b 00    movw   $0x26c,0xb8004(%rip)        # 1b803f <start+0xb801f>
  100039:   6c 02 
  10003b:   66 c7 05 06 80 0b 00    movw   $0x26c,0xb8006(%rip)        # 1b804a <start+0xb802a>
  100042:   6c 02 
  100044:   66 c7 05 08 80 0b 00    movw   $0x26f,0xb8008(%rip)        # 1b8055 <start+0xb8035>
  10004b:   6f 02 
  10004d:   66 c7 05 0a 80 0b 00    movw   $0x22c,0xb800a(%rip)        # 1b8060 <start+0xb8040>
  100054:   2c 02 
  100056:   66 c7 05 0c 80 0b 00    movw   $0x220,0xb800c(%rip)        # 1b806b <start+0xb804b>
  10005d:   20 02 
  10005f:   66 c7 05 0e 80 0b 00    movw   $0x277,0xb800e(%rip)        # 1b8076 <start+0xb8056>
  100066:   77 02 
  100068:   66 c7 05 10 80 0b 00    movw   $0x26f,0xb8010(%rip)        # 1b8081 <start+0xb8061>
  10006f:   6f 02 
  100071:   66 c7 05 12 80 0b 00    movw   $0x272,0xb8012(%rip)        # 1b808c <start+0xb806c>
  100078:   72 02 
  10007a:   66 c7 05 14 80 0b 00    movw   $0x26c,0xb8014(%rip)        # 1b8097 <start+0xb8077>
  100081:   6c 02 
  100083:   66 c7 05 16 80 0b 00    movw   $0x264,0xb8016(%rip)        # 1b80a2 <start+0xb8082>
  10008a:   64 02 
  10008c:   66 c7 05 18 80 0b 00    movw   $0x221,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   $0x248,0xb8000(%rip)        # 1b8009 <header_end+0xb7ff1>
  100007:   48 02 
  100009:   66 c7 05 02 80 0b 00    movw   $0x265,0xb8002(%rip)        # 1b8014 <header_end+0xb7ffc>
  100010:   65 02 
  100012:   66 c7 05 04 80 0b 00    movw   $0x26c,0xb8004(%rip)        # 1b801f <header_end+0xb8007>
  100019:   6c 02 
  10001b:   66 c7 05 06 80 0b 00    movw   $0x26c,0xb8006(%rip)        # 1b802a <header_end+0xb8012>
  100022:   6c 02 
  100024:   66 c7 05 08 80 0b 00    movw   $0x26f,0xb8008(%rip)        # 1b8035 <header_end+0xb801d>
  10002b:   6f 02 
  10002d:   66 c7 05 0a 80 0b 00    movw   $0x22c,0xb800a(%rip)        # 1b8040 <header_end+0xb8028>
  100034:   2c 02 
  100036:   66 c7 05 0c 80 0b 00    movw   $0x220,0xb800c(%rip)        # 1b804b <header_end+0xb8033>
  10003d:   20 02 
  10003f:   66 c7 05 0e 80 0b 00    movw   $0x277,0xb800e(%rip)        # 1b8056 <header_end+0xb803e>
  100046:   77 02 
  100048:   66 c7 05 10 80 0b 00    movw   $0x26f,0xb8010(%rip)        # 1b8061 <header_end+0xb8049>
  10004f:   6f 02 
  100051:   66 c7 05 12 80 0b 00    movw   $0x272,0xb8012(%rip)        # 1b806c <header_end+0xb8054>
  100058:   72 02 
  10005a:   66 c7 05 14 80 0b 00    movw   $0x26c,0xb8014(%rip)        # 1b8077 <header_end+0xb805f>
  100061:   6c 02 
  100063:   66 c7 05 16 80 0b 00    movw   $0x264,0xb8016(%rip)        # 1b8082 <header_end+0xb806a>
  10006a:   64 02 
  10006c:   66 c7 05 18 80 0b 00    movw   $0x221,0xb8018(%rip)        # 1b808d <header_end+0xb8075>
  100073:   21 02 
  100075:   f4                      hlt    

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

2 个答案:

答案 0 :(得分:2)

多重启动规范说:

  

Multiboot标头必须完全包含在第一个内   OS映像的8192个字节,并且必须是长字(32位)对齐。

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版本进行,由于文件布局的原因,它只是偶然的。

答案 1 :(得分:1)

除了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"