如何加载更多扇区并在加载的扇区中调用函数

时间:2013-11-24 09:17:17

标签: assembly x86 nasm bootloader bios

我用

汇总了以下代码
nasm -f bin option

并将其放入软盘映像,然后使用virtualbox运行

我的目标是call print_word

但我怎么能call print_word来这里?

要学习如何调用额外扇区中的函数,

我将print_word放入第二个有意图的部门。

提前致谢。

main.asm中:

org 0x7c00
start:
    mov ax, 0x0206
    mov cx, 0x0002
    mov dx, 0x0000

    mov bx, 0x7e00
    push bx
    pop es

    mov bx, 0
.try_again:
    int 13h
    jc .try_again

    mov ax, 0xabcd
    push ax
    jmp 0x7e00


jmp $

times 510 - ($-$$) db 0
dw 0xaa55

more:
    %include "./common/print_word.asm"

print_word.asm:

;print_word(word)
print_word:
    push bp
    mov bp, sp

    push word [bp+4]
    call print_word_1

    push word [bp+4]
    call print_word_2
    push word [bp+4]
    call print_word_3
    push word [bp+4]
    call print_word_4
    mov sp, bp
    pop bp
    ret


print_word_1:
    push bp
    mov bp, sp

    mov ah, 0x0e
    mov byte al, [bp+4]
    shr al, 4
    cmp al, 0x0a
    jl .num
    sub al, 0x0a
    jmp .char
.num:
    add al, '0' 
    jmp .put
.char:
    add al, 'A'
    jmp .put
.put:
    int 10h
    mov sp, bp
    pop bp
    ret

print_word_2:
    push bp
    mov bp, sp

    mov ah, 0x0e
    mov byte al, [bp+4]
    shl al, 4
    shr al, 4
    cmp al, 0x0a
    jl .num
    sub al, 0x0a
    jmp .char
.num:
    add al, '0' 
    jmp .put
.char:
    add al, 'A'
    jmp .put
.put:
    int 10h
    mov sp, bp
    pop bp
    ret


print_word_3:
    push bp
    mov bp, sp

    mov ah, 0x0e
    mov byte al, [bp+5]
    shr al, 4
    cmp al, 0x0a
    jl .num
    sub al, 0x0a
    jmp .char
.num:
    add al, '0' 
    jmp .put
.char:
    add al, 'A'
    jmp .put
.put:
    int 10h
    mov sp, bp
    pop bp
    ret

print_word_4:
    push bp
    mov bp, sp

    mov ah, 0x0e
    mov byte al, [bp+5]
    shl al, 4
    shr al, 4
    cmp al, 0x0a
    jl .num
    sub al, 0x0a
    jmp .char
.num:
    add al, '0' 
    jmp .put
.char:
    add al, 'A'
    jmp .put
.put:
    int 10h
    mov sp, bp
    pop bp
    ret

1 个答案:

答案 0 :(得分:0)

使用常规CALL指令。你的汇编程序将使用位移而非绝对地址组装一个CALL NEAR。像这样:

mov ax,0xabcd
push ax
call print_word
add sp,2  ;to restore the stack

jmp $

另请注意,在调用print_word routineprint_word_1等时,您的print_word_2无法正常恢复堆栈。您的调用约定要求调用者删除它在堆栈上推送的参数,因此在每个call print_word_N指令之后,您必须通过发出add sp,2指令或弹出最后一个堆栈来恢复堆栈元素进入未使用的寄存器。例如,像这样:

由于传递给不同print_word_N例程的值总是相同的,并且您的例程不会更改参数的值,您可以通过假设参数已经在堆栈中的第二个来优化代码大小以及随后的电话:

print_word:
    push bp
    mov bp, sp

    push word [bp+4]
    call print_word_1
    call print_word_2
    call print_word_3
    call print_word_4
    mov sp, bp
    pop bp
    ret
BTW:别忘了这是一台小端机器。您正在转换为十六进制并在[ebp+4]处打印字节,然后在[ebp+5]处打印字节。这将导致屏幕上显示CDAB。十六进制数的两个最左边的数字位于[ebp+5]的字节中,因此您应首先打印它们,然后将数字存储在字节[ebp+4]

啊!关于加载扇区:您的错误是您如何考虑加载扇区的块的段和偏移量。您希望在0000:7E00加载下一个扇区,即加载的前512个字节的代码旁边。相反,您将它加载到7E00:0000,这根本不是相同的地址。

更新和修复的代码如下(加载下一个扇区的部分):

org 0x7c00
start:
    mov ax, 0   ;segment is 0
    mov ds, ax
    mov es, ax

.try_again:
    mov ax, 0x0201  ;load 1 sector
    mov cx, 0x0002  ;located at sector 2
    mov dx, 0x0000
    mov bx, 0x7e00  ;into 0000:7E00
    int 13h
    jnc .ok
.errorsector:
    mov ax,0   ;reset floppy controller ir error
    int 13h
    jmp .try_again

.ok:
    mov ax, 0xabcd
    push ax
    call print_word
    add sp,2

    jmp $