0

最近几天我尝试制作一个引导加载程序,结果如下:

BITS 16


;CONSTANTS
BOOTSEG     equ 07C0h
STACKSEG    equ 1BC0h ; BOOTSEG + 512 Byte (bootloader) + 512 Byte (second stage) + 4096 Byte (buffer) = 1BC0h
STACKSIZE   equ 0400h ; 1KB stack



; INIT
    mov AX, BOOTSEG     
    mov DS, AX      ; set data segment to adress where bootloader will be loaded to
    mov AX, STACKSEG
    cli         ; disable interrupts while set up stack
    mov SS, AX  
    mov SP, STACKSIZE   ; set up stack
    sti         ; restore interrupts
    mov [bootdev], DL   ; save boot device number

;START
    mov SI, string      ; get the adress of the string to print into SI 
    call _printstring

;LOAD 2nd STAGE
    mov AH, 02h     ; int 13h subfunction ah=02
    mov AL, 01h     ; read 1 sector
    mov CX, 02h     ; begin read at track 0, sector 2
    mov DH, 00h     ; head = 0 ????
    mov DL, [bootdev]   ; read from boot device
    mov BX, BOOTSEG     
    add BX, 512
    mov ES, BX      ; write second stage right after first stage
    mov BX, 00h


    int 13h         ; do it
    jc fail
    mov SI, success     ; OK
    call _printstring


    jmp 09C0h:0000h     ; jump to second stage, execute it
                ; does not work:
                    ; 1)    jmp ES:BX
                    ;
                    ; 2)    push ES
                    ;   push BX
                    ;   retf



fail:   
    mov SI,error        ; error on reading second stage
    call _printstring



loop:   
    jmp loop        ; infinite loop at the end


_printhex:
; AX: hex value to print
; Modifies: AX, BX, DX, CX

    mov CX, 4
start:  mov DX, 00h
    mov BX, 10h
    div BX
    cmp DX, 9
    jg letter
    add DL, 30h
    jmp store

letter: add DL, 37h

store:  push DX
    dec CX
    jnz start
    mov CX,4

print:  pop AX
    call _printchar
    dec CX
    jnz print 
    mov AL, 13
    call _printchar
    mov Al, 10
    call _printchar 
    ret






_printchar:
; print char in AL
; Modifies: AX, BX

    mov AH, 0Eh
    mov BX, 07h
    int 10h
    ret




_printstring:
; SI : start adress of string
; Modifies: AX , BX , SI

m1: lodsb           ; Loads [SI] into AL and increases SI by one    
    or AL, AL       ; check if AL = 0
    jz finish       ; then finish
    call _printchar     ; else print charakter
    jmp m1

finish: 
    ret         ; return from the printstring call






;DATA
    string db 'Started my first Bootloader', 13, 10, 0
    success db 'Success', 13, 10, 0
    error db 'Error', 13, 10, 0
    bootdev db 0




; MAKE BOOTSECTOR
    times 510-($-$$) db 0       ; fill up the sector to 512 - 2 = 510 bytes
    dw 0AA55h           ; set the two bootsector identifying bytes





; SECOND STAGE
    add BX, 10
    mov AL, 'A'
    mov AH, 0Eh 
    mov BX, 07h
    int 10h     ; test output

loop2:
    jmp loop2   ; infinite loop at the end

现在我有两个问题:

  1. 在第 43 行,我必须使用带绝对地址的跳转,但我想使用ESand的值BX。因此,我尝试了您可以在评论中看到的两种替代方案,但它们对我不起作用。我究竟做错了什么?

  2. 我对低级编程很陌生。我的代码中是否存在一些重大或次要错误?有没有我没有考虑过的代码风格约定?

我不想格式化代码,所以这里是 asm 文件的链接,你可以用你最喜欢的编辑器阅读它: https ://www.dropbox.com/s/i3jpprf66nlmzz2/mybootloader.asm?m

4

2 回答 2

6
jmp 09C0h:0000h

push ES
push BX
retf

应该同样有效(当然,在后一种情况下提供ES=9C0h 和BX=0)。

并且jmp ES:BX不是一个有效的指令,或者,至少,它不会做你可能期望的事情。

可能出现的问题:

  • 9C0h:0 是错误的地址
  • 您在 9C0h:0 处没有预期的代码(读取失败或您要求 BIOS 将读取的数据存储在不同的位置)
  • 9C0h:0 处的代码未编译为在偏移量 0 处开始执行(请记住,x86 机器代码通常与位置无关)
  • 别的东西,可能是代码/数据损坏或未初始化的变量/寄存器
于 2013-03-06T13:18:34.373 回答
1

我发现了这个错误。一个非常愚蠢的错误:在触发中断之前,_printstring 函数覆盖了 BX 寄存器。我修复了它,现在跳转确实像 Alexey Frunze 所描述的那样工作 - 谢谢:

推ES

推BX

回复

此外,我在段寻址方面犯了一个错误(也感谢 Alexey Frunze):我想在 512 字节长的第一阶段之后立即加载第二阶段。所以提到段/偏移地址(物理地址 = 16 * 段 + 偏移)我必须将 512/16 = 32 = 20H 添加到 07C0。所以值必须是:ES = 07E0H 和 BX = 0000H

于 2013-03-11T23:05:25.313 回答