[英]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
我以兩種不同的方式運行它:
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.