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