2

我必须在汇编中定义一个函数,它允许我循环一串声明的字节并使用 BIOS 中断打印它们。我是16位实模式。这是一个从教科书中编写一个小引导加载程序的练习,但它似乎只是一个草稿,它缺少一些东西。我得到了以下代码:

org 0x7c00

mov bx, HELLO_MSG
call print_string

mov bx, GOODBYE_MSG
call print_string

jmp $                ;hang so we can see the message

%include "print_string.asm"

HELLO_MSG:
    db 'Hello, World!', 0

GOODBYE_MSG:
    db 'Goodbye!', 0

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

我的 print_string.asm 看起来像这样:

print_string:
    pusha
    mov ah, 0x0e

    loop:
        mov al, bl
        cmp al, 0
        je return
        int 0x10
        inc bx
        jmp loop

    return:
        popa
        ret

我对自己在做什么有一些想法,但是这本书没有解释如何迭代某些东西。我知道如何在 C 中做到这一点,但这是我第一次将汇编用于调试 C 代码以外的其他事情。当我通过模拟器启动时会发生什么,它会打印出几行乱码,并最终挂在那里让我看到我的失败。哈哈哈。

4

2 回答 2

3

好吧,看起来它在调用函数之前将字符串的地址加载到 BX 寄存器中。

实际的函数看起来像是在尝试遍历字符串,使用 BX 作为指针并递增它(inc bx),直到它在字符串末尾遇到 ASCII NUL(cmp al, 0; je return)...

……但有些不对劲。“mov al, bl”指令看起来不正确,因为这会将地址的低 8 位移动到 al 中,以便与 ASCII NUL 进行比较,这没有多大意义。我认为它应该更像是“mov al,[bx]”;即将BX 地址引用的字节移动到AL 寄存器中——尽管我已经很长时间没有使用汇编了,所以我的语法可能不正确。

由于该错误,10h 中断还将根据字符串的地址而不是字符串的内容打印随机字符。这可以解释你所看到的胡言乱语。

于 2013-09-11T01:07:55.353 回答
1

我认为问题在于您不能指望int保留任何寄存器,因此您需要保护它们。另外,史蒂文指出的关于加载字符串地址的内容:

; Print the string whose address is in `bx`, segment `ds`
; String is zero terminated
;
print_string:
    pusha

loop:
    mov   al, [bx]    ; load what `bx` points to
    cmp   al, 0
    je    return
    push  bx          ; save bx
    mov   ah, 0x0e    ; load this every time through the loop
                      ; you don't know if `int` preserves it
    int   0x10
    pop   bx          ; restore bx
    inc   bx
    jmp   loop

return:
    popa
    ret
于 2013-09-11T01:17:46.970 回答