簡體   English   中英

為什么我的引導加載程序不能從 memory 正確加載一個字節?

[英]Why does my bootloader not load a byte from memory correctly?

我有以下 x86 程序:

mov ah, 0x0e          ; Set up call to BIOS routine to print character

mov al, [character]   ; Stick the byte at label "character"
int 0x10              ; Display character in al

jmp $                 ; Loop forever

character:
db 0x41               ; Put the byte "A" at this position

times 510-($-$$) db 0 ; Pad with zeros and end with the magic number for a bootloader
db 0x55
db 0xaa

我以兩種不同的方式運行它:

  • 在qem
  • 使用dd將其寫入 USB 棒並在舊的 64 位筆記本電腦上啟動

我使用以下命令來運行此代碼:

$ nasm -f bin -o boot.bin main.s
$ qemu-system-x86_64 boot.bin  # to test
$ dd if=boot.bin of=/dev/sda # to put it on a USB stick

上面寫的代碼在這兩種情況下都不起作用。 在硬件上它顯示一個閃爍的光標,在 qemu 上它打印一個西里爾字母,而不是“A”。 所以我將第二行(非空)更改為

mov al, [0x7c00 + character]

將偏移量0x7c00添加到 label,因為根據某些消息來源,x86 將引導加載程序放在0x7c00中的 0x7c00。 這在 qemu 中按預期工作,但在硬件上繼續給我一個閃爍的 cursor。 請注意,這與將[org 0x7c00]放在頂部具有相同的效果,我的意思是使用上述行或通過添加org指令生成的二進制文件是相同的(我比較了它們的 md5s)。

為了確保我的硬件沒有一些奇怪的字符集,其中0x41不是“A”,我嘗試了

mov al, 0x41

這適用於 qemu 和硬件。

如何正確引用存儲在“字符”中的數據,以便我的筆記本電腦找到應該存在的值? 請注意,因為這是一個引導加載程序,所以 CPU(如果我理解正確的話)處於 16 位實模式。

x86 具有多個包含 memory 偏移量的段寄存器 在實模式(和其他模式?)中,這些寄存器被隱式添加到您所做的任何 memory 參考中。 使用哪個段寄存器取決於上下文(換句話說,地址用於哪種指令)。 在我們的例子中,當我們嘗試從 memory 獲取數據時

mov al, [character]

處理器將隱式地將ds (用於“數據段”)寄存器的內容(乘以 16)添加到 memory 偏移character 請注意,這發生在運行時,而不是編譯時,因此如果您反匯編它,您將不會在二進制文件中看到它。

解決方案是在匯編程序的頂部將ds清零。 但是,請注意,您實際上不能只說mov ds, 0因為 x86 不支持將常量寫入段寄存器 - 您必須通過另一個寄存器 go

mov ax, 0
mov ds, ax

為了完整起見,這是在我的筆記本電腦和 QEMU 上都可以使用的完整更新代碼。 下面評論了與問題中代碼的差異。

mov ax, 0  ; Zero out the data segment register
mov ds, ax ;

mov ah, 0x0e

mov al, [0x7c00 + character] ; Add 0x7c00 to the offset
                             ; As mentioned in the question, putting ORG 0x7C00 at the top of the file
                             ; also works (and is better, but this is clearer for demonstration purposes)
                             ; and in fact produces an identical binary to this explicit addition.
int 0x10

jmp $

character:
db 0x41

times 510-($-$$) db 0
db 0x55
db 0xaa

顯然,這里發生的事情是ds寄存器在 QEMU 上默認為零,但在我的硬件上卻沒有。 由專業人士編寫的真正引導加載程序總是會明確地將這類事情歸零,而不是假設 BIOS 在加載其代碼之前將寄存器放在任何特定的 state 中。

如果您像我一樣一直在閱讀Nick Blundell 的“Writing a Simple Operating System - from Scratch” ,他實際上稍后會在第 3.6.1 節(“Extended memory access using segments”)中談到這些內容。 不幸的是,在那之前我被困在這幾頁上,沒有提前閱讀。

也許你丟失了一些參數和 ORG 命令

嘗試這個

org 0x7c00            ; Tell NASM ,This program begin at Address 0x7c00

mov ah, 0x0e          ; Set up call to BIOS routine to print character

mov al, [character]   ; Stick the byte at label "character"

mov bh,0              ; The PAGE 0

mov bl,0xff           ; White

int 0x10              ; Display character in al

jmp $                 ; Loop forever

character:

db 0x41               ; Put the byte "A" at this position

times 510-($-$$) db 0 ; Pad with zeros and end with the magic number for  a bootloader

db 0x55

db 0xaa

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM