[英]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:
它提供了多引導頭以及以下內容:
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匯編程序版本有一個重疊的.boot和.text段,所以在加載文件時grub可能會用.text部分的數據覆蓋.boot部分。 任何人都知道如何解決這個問題?
多引導規范說:
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
版本也應該這樣做,由於文件布局,它只是意外地在那里工作。
除了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"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.