实模式下的NASM远距离/远距离呼叫和ASM代码约定

obr*_*orf 0 x86 assembly nasm bootloader

最近几天,我试图制作一个引导程序,这是结果:

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
Run Code Online (Sandbox Code Playgroud)

现在我有两个问题:

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

  2. 我对低级编程非常陌生。我的代码中是否存在一些主要或次要错误?是否有我未考虑的代码样式约定?

我不想格式化代码,因此这是asm文件的链接,您可以使用自己喜欢的编辑器进行阅读:https : //www.dropbox.com/s/i3jpprf66nlmzz2/mybootloader.asm?m

Ale*_*nze 5

jmp 09C0h:0000h
Run Code Online (Sandbox Code Playgroud)

push ES
push BX
retf
Run Code Online (Sandbox Code Playgroud)

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

jmp ES:BX不是有效的指令,或者至少不会做您可能期望得到的指令。

可能的问题:

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