Написание ОС. Странная ошибка

Пишу свою ОС. Вроде всё идёт хорошо (наверное даже слишком). Проблема в том, что управление на вторую часть загрузчика передаётся сразу после считывания секторов диска. Как такое возможно?

  • boot1.asm:
[bits 16]
[org 0x7c00]
    jmp boot

BOOT2_OFFSET    equ 0x1000

boot:
    mov [BOOT_DRIVE], dl

    mov bx, MSG_BOOT1
    call print
    call print_nl

    call load_boot2

    jmp $

load_boot2:
    mov bx, MSG_BOOT2_LOAD
    call print
    call print_nl

    mov bx, BOOT2_OFFSET
    mov dh, 16
    mov dl, [BOOT_DRIVE]
    call disk_load

    jmp $

%include "disk.asm"
%include "print.asm"

BOOT_DRIVE      db 0
MSG_BOOT1       db "Loading in BOOT1...", 0
MSG_BOOT2_LOAD  db "Loading BOOT2.bin...", 0

times 510 - ($ - $$) db 0
dw 0xaa55
  • disk.asm:
; load 'dh' sectors from drive 'dl' into ES:BX
disk_load:
    pusha
    push dx

    mov ah, 0x02
    mov al, dh
    mov cl, 0x02
    mov ch, 0x00
    mov dh, 0x00

    int 0x13
    jc disk_error
    jnc disk_success

    pop dx
    cmp al, dh
    jne sectors_error
    popa
    ret

disk_success:
    mov bx, DISK_SUCCESS
    call print
    call print_nl
    ret

disk_error:
    mov bx, DISK_ERR
    call print
    call print_nl
    jmp $

sectors_error:
    mov bx, SECT_ERR
    call print
    jmp $

DISK_ERR:       db "Disk read error!", 0
SECT_ERR:       db "Incorrect number of sectors read!", 0
DISK_SUCCESS:   db "Disk read success!", 0
  • print.asm:
print:
    pusha

start:
    mov al, [bx]
    cmp al, 0 
    je done
    add bx, 1
    jmp start

done:
    popa
    ret

print_nl:
    pusha
    
    mov ah, 0x0e
    mov al, 0x0a
    int 0x10
    mov al, 0x0d
    int 0x10
    
    popa
    ret
  • boot2.asm
[bits 16]
[org 0x1000]
    jmp boot2

boot2:
    mov bx, MSG_BOOT2
    call print
    call print_nl

    jmp $

%include "print.asm"

MSG_BOOT2       db "Loading in BOOT2...", 0
  • Вывод qemu:

File1

  • Собираю так:

    1. nasm boot1.asm -f bin -o boot1.bin
    2. nasm boot2.asm -f bin -o boot2.bin
    3. cat boot1.bin boot2.bin > os.bin
    4. qemu-system-i386 -fda os.bin

Ответы (1 шт):

Автор решения: Fat-Zer

В disk_load в стек сохраняются регистры и dx (и собственно зачем dx отдельно сохранять?):

disk_load:
    pusha
    push dx

но в ветке disk_success они оттуда не достаются:

disk_success:
    mov bx, DISK_SUCCESS
    call print
    call print_nl
    ret

Вот при ret'е и происходит переход по адресу, который был до этого в dx, а это 0x1000 (dh=16 dl=0), что очень «удобно» т.к. это совпадает с тем адресом, куда загружается вторая часть загрузчика...

→ Ссылка