Disk Okuma İşlevi Bootloader'da Beklendiği Gibi Çalışmıyor
Temel bir önyükleyici geliştirmeye çalışıyorum, ancak bir sabit sürücüden ek sektörleri okumak için bir işlev oluşturmaya çalıştığımda bir sorunla karşılaştım. NASM'de Kali Linux üzerinde geliştiriyorum ve emülatörüm olarak QEMU kullanıyorum. Bu benim ana önyükleyici dosyam:
[org 0x7c00]
mov bp, 0x8000
mov sp, bp
call read_disk
mov si, my_string
call print ;prints a string, si points to the string to be printed
jmp $ read_disk mov ah, 0x02 ;read from disk mov al, 0x01 ;read one sector mov ch, 0x00 ;read from cylinder 0 mov dh, 0x00 ;read from head 0 mov cl, 0x02 ;read the second sector mov bx, 0 mov es, bx mov bx, 0x7c00+512 int 0x13 jc disk_error ;BIOS sets the carry flag if disk read was unsuccessful ret disk_error: mov si, error_msg call print jmp $
;
;Functions
;
%include "functions/print.asm"
%include "functions/print_hex.asm"
%include "functions/print_nl.asm"
%include "functions/calc_len.asm"
%include "functions/find_string.asm"
;
;Data
;
error_msg:
db 'Error reading disk', 0
times 510-($-$$) db 0 ;pad out the rest of the bootloader with zeros to increase the size to 512 bytes
dw 0xaa55 ;Magic bytes so BIOS recognizes the hard drive as bootable
;
;SECOND SECTOR
;
my_string:
db 'Disk read successful', 0
times 512 db 0 ;need to pad out the rest of the sector with zeros since QEMU requires it
Gördüğünüz gibi my_string
, taklit edilen sabit diskin ikinci sektöründe 512 bayttan sonra yatıyor. Ancak önyükleyiciyi derleyip çalıştırdığımda hiçbir şey çıktı vermiyor. Yukarıda verdiğim kodda , işlev my_string
bittikten sonra yazdırıyorum read_disk
. Ama garip bir şekilde , fonksiyonun my_string
içine yazdırılan iki satırı hareket ettirirsem işe yarıyor. Bu, çalışan koddur:
[org 0x7c00]
mov bp, 0x8000
mov sp, bp
call read_disk
jmp $ read_disk mov ah, 0x02 ;read from disk mov al, 0x01 ;read one sector mov ch, 0x00 ;read from cylinder 0 mov dh, 0x00 ;read from head 0 mov cl, 0x02 ;read the second sector mov bx, 0 mov es, bx mov bx, 0x7c00+512 int 0x13 jc disk_error ;BIOS sets the carry flag if disk read was unsuccessful mov si, my_string call print ;prints a string, si points to the string to be printed ret disk_error: mov si, error_msg call print jmp $
;
;Functions
;
%include "functions/print.asm"
%include "functions/print_hex.asm"
%include "functions/print_nl.asm"
%include "functions/calc_len.asm"
%include "functions/find_string.asm"
;
;Data
;
error_msg:
db 'Error reading disk', 0
times 510-($-$$) db 0 ;pad out the rest of the bootloader with zeros to increase the size to 512 bytes
dw 0xaa55 ;Magic bytes so BIOS recognizes the hard drive as bootable
;
;SECOND SECTOR
;
my_string:
db 'Disk read successful', 0
times 512 db 0 ;need to pad out the rest of the sector with zeros since QEMU requires it
Biri bana bu tuhaf tuhaflığı açıklayabilirse çok minnettar olurum.
Yanıtlar
Belleğe okumadan önce sadece SP olarak değil SS: SP'yi ayarlamalısınız . SS sıfır olabilir veya olmayabilir. Eğer SS 0x0000 olur sonra yığını 0x0000 yer almaktadır: 0x8000 ve oradan aşağı büyüyecektir.
Kodunuz, diskteki ikinci 512 bayt sektörünü 0x0000: 0x7e00 belleğine okur ve disk_read
bu, yığına 0x0000: 0x7ffe'den 0x0000: 0x7fff'ye yerleştirilen işlevin dönüş adresini içeren tüm baytları içerir .
Yığını int 0x13
bozduğunuzdan beri, iç veriler, dönüş adresi ve bayraklar bozulmuş olduğundan büyük olasılıkla asla geri dönmeyecektir. Yığını bu şekilde bozmak, öngörülemeyen sonuçlar doğuracaktır. Önyükleyiciden sonra yüklediğiniz veri ve koda müdahale etmemek için yığını, önyükleyicinin altına 0x0000: 0x7c00 koymayı düşünün.
Not: İhtiyaç duyduğunuz tüm segment kayıtlarını beklediğiniz değerlere ayarlamalısınız. Belirli bir değer içeren segment kayıtlarından hiçbirine güvenmemelisiniz. BIOS, çoğu emülatörde 0x0000 olmasına rağmen değerlerini garanti etmez.