我正在制作引導加載程式,作為我學習匯編的一種方式。我已經研究過使用部分來組織和優化我的代碼,但是當我呼叫我的 printf 函式時,一件事不起作用。當我在 .data 部分中有我的 HELLO_WORLD 字串時,它根本不想加載該字串
; Set Code to run at 0x7c00
org 0x7c00
; Put into real mode
bits 16
; Variables without values
section .bss
; Our constant values
section .data
HELLO_WORLD: db 'Hello World!', 0
; Where our code runs
section .text
_start:
mov si, HELLO_WORLD ; Moves address for string into si register
call printf ; Calls printf function
jmp $ ; Jump forever
printf:
lodsb ; Load the next character
cmp al, 0 ; Compares al to 0
je _printf_done ; If they are equal...
call print_char ; Call Print Char
jmp printf ; Jump to the loop
_printf_done:
ret ; Return
print_char:
mov ah, 0x0e ; tty mode
int 0x10 ; Video interrupt
ret ; Return
; Fills the rest of the data with 0
times 510-($-$$) db 0
; BIOS boot magic number
dw 0xaa55
結果:
Booting into hard drive...
但是,如果我將字串移到外面并將其放在 printf 的底部,它似乎可以作業。
; Set Code to run at 0x7c00
org 0x7c00
; Put into real mode
bits 16
; Variables without values
section .bss
; Our constant values
section .data
; Where our code runs
section .text
_start:
mov si, HELLO_WORLD ; Moves address for string into si register
call printf ; Calls printf function
jmp $ ; Jump forever
printf:
lodsb ; Loads next character
cmp al, 0 ; Compares al to 0
je _printf_done ; If they are equal...
call print_char ; Call Print Char
jmp printf ; Jump to the loop
_printf_done:
ret ; Return
print_char:
mov ah, 0x0e ; tty mode
int 0x10 ; Video interrupt
ret ; Return
HELLO_WORLD: db 'Hello World!', 0
; Fills the rest of the data with 0
times 510-($-$$) db 0
; BIOS boot magic number
dw 0xaa55
結果:
Booting into hard drive...
Hello World!
這是為什么?
uj5u.com熱心網友回復:
$ - $$計算section內的.text位置,因此您填充.text到 510 位元組 2 位元組簽名。因此,該.data部分在引導簽名之后結束,而不是引導扇區的一部分。
我通過查看檔案大小注意到了這一點:525 位元組。使用 hexdump 查看發生了什么:
$ nasm -fbin bad.asm
$ hd bad # equivalent to hexdump -C
00000000 be 00 7e e8 02 00 eb fe ac 3c 00 74 05 e8 03 00 |..~......<.t....|
00000010 eb f6 c3 b4 0e cd 10 c3 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 00 |Hello World!.|
我們看到Hello World!ASCII 位元組從檔案中的偏移量 512 開始,因此它不是韌體在傳統 BIOS 模式下啟動時將加載的第一個 512 位元組扇區的一部分。
平面二進制檔案沒有節或 ELF 或 PE 程式段,并且將加載具有讀 寫 執行權限的所有內容(CPU 處于實模式,因此沒有分頁或段權限)。從創建平面二進制檔案的角度考慮可能最容易,并且您將內容放在前 512 個位元組內,而不是根據可執行檔案的 .data 和 .text 部分。
你可以把你的, 因為緊跟在你的 MBR 加載的地方(線性地址 0x7C00)之后的空間往往可以免費使用section .bss 。dw 0xaa55將它放在源代碼中的引導簽名之后,可以使您的源代碼與 NASM 布局平面二進制檔案的方式相匹配。請注意,它不會像 .bss 空間在主流作業系統下那樣對您進行零初始化。
如果你真的想使用section指令并且在你的代碼之后但在引導簽名之前有一些.rodata或.data,你需要做一些除了$-$$.
就像可能在每個部分的開始/結束處放置標簽,這樣你就可以做totalsize equ (text_end-text_start) (data_end-data_start)// times (510-totalsize) db 0。dw 0xaa55但是您必須在 NASM 放在最后的任何部分中執行此操作,否則您會將某些部分推出超過 512 位元組邊界。幸運的是,檔案大小提供了一個簡單的檢查。
您可以控制 NASM 在平面二進制檔案中的布局順序。這是 NASM 的一種特殊情況。它充當聯結器和匯編器,填充符號偏移量,而不僅僅是制作重定位條目。在新部分第一次出現時使用屬性start=x和指令。(感謝@ecm 指出這一點。)但默認設定已經先訂購,這是您所需要的,因為執行從 MBR 的第一個位元組開始。follows=ysection.text
起初,我假設 NASM 會按首次出現的順序將這些部分輸出到您的平面二進制檔案中,在這種情況下,問題將是執行db 'Hello World!', 0as machine code。
事實證明這不是 NASM 所做的。它將.text部分放在平面二進制檔案中的第一位,即使section .data在源代碼中也是如此。
順便說一句,您的引導加載程式依賴于一些無法保證的東西,并且會在某些 BIOS 上失敗。
org在使用lodsbto load from之前,您不會初始化 DS 或 ES 以匹配您的設定DS:SI。您不要
cld在回圈之前確保lodsb將增加 SI 而不是減少。與 32 位和 64 位模式下的標準呼叫約定/ABI 不同,您不能假設 DF=0 進入引導加載程式。事實上,盡可能少地假設它被加載到線性地址 7C00h 并且 DL = 您可以用來從同一設備加載更多扇區的驅動器號。有關本期和上期的資訊,請參閱Michael Petch 的引導加載程式開發一般技巧。
int 10h在呼叫/AH=0Eh( https://en.wikipedia.org/wiki/INT_10H / http://www.ctyme.com/intr/rb-0106.htm )之前,您沒有將 BH/BL 設定為頁碼/顏色. 看- 如何使用 INT 10H 顯示暫存器值
- 使用 DOS 或 BIOS 顯示字符
- 呼叫int 10h時bl的值
您不會為 BPB 留出空間,因為 BIOS 從位元組 #3 開始在扇區的某些位元組上亂涂亂畫。(請參閱上面 Michael Petch 的一般提示。)這在 QEMU 和 Bochs 上很好,但如果從 USB 引導,在某些真實硬體上會失敗。
(Bochs 通常被推薦用于引導加載程式的單步除錯。特別是如果您對分段或切換到保護模式進行任何操作;連接到 Qemu 的 GDB 不像 Bochs 那樣知道分段。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/528545.html
上一篇:需要在XamarinWebview應用程式上實作SetSupportMultipleWindows
下一篇:如何在MASM中跨段填充塊?
