使用无预定义功能在装配中打印字符串

时间:2013-09-11 00:54:36

标签: string loops assembly x86 bootloader

我必须在程序集中定义一个函数,它允许我遍历一串声明的字节并使用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代码。当我通过模拟器启动时会发生什么,它打印出几行乱码并最终挂在那里让我看到我失败的所有荣耀。哈哈哈。

2 个答案:

答案 0 :(得分:2)

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

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

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

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

答案 1 :(得分: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