我正在开发x86引导扇区中的代码,作为学习OS开发的一部分。我期待我的代码将其打印到控制台:
您好
我得到了这个:
ħ
为什么只打印一个字符而不是整个字符串?我该如何解决这个问题?
这是我的代码片段:
mov ah, 0x0e
mov bx, string_p
add bx, 0x7c00
mov al, [bx]
int 0x10
jmp $
string_p:
db 'Hello',0
"then padding and magic number"
答案 0 :(得分:3)
将注册10H
设置为AH
(INT 21h/AH=0eh)的中断0EH
将在寄存器AL
中打印当前字符。 Ralf Brown的Interrupt List被认为是DOS和BIOS中断的圣经。它是关于可用中断,工作方式和副作用的宝贵信息来源。
如果您使用 INT 21h / AH = 0eh ,您需要手动推进每个字符的字符串指针,并逐个打印出来。像这样的代码应该有效:
org 0x7c00 ; starting address
bits 16 ; 16-Bit mode
main:
cli ; disable interrupts
cld ; clear direction flags
xor ax, ax ; set AX to 0
mov ds, ax ; set DS to 0
mov ah, 0x0e ; call 0EH bios call
mov si, string ; move starting address of `string` into SI
loop:
lodsb ; load byte at DS into AL, update (increment) SI
or al, al ; check if AL is 0 (ORing will do nothing, but set the right flags
jz hltloop ; if zero jump to end
int 0x10 ; do the print call
jmp loop ; jump back to loop start
hltloop:
hlt ; halt and catch fire
jmp hltloop ; jump back to halt, if an interrupt occurred anyway
string:
db 'Hello',0
times 510-($-$$) db 0
dw 0xAA55
此示例使用LODSB指令读取字符串的每个字符。 LODS 指令记录为:
分别从源操作数将字节,字或双字加载到 AL ,AX或EAX寄存器中。源操作数是一个存储单元,其地址从DS:ESI或 DS:SI 寄存器中读取(取决于指令的地址大小属性,32或 16) ,分别)。可以使用段覆盖前缀覆盖DS段。
答案 1 :(得分:0)
这已经晚了,但可能对某人有所帮助。我在ubuntu上开发os时遇到了同样的问题。这对我有用。我创建了一个打印函数,并在将字符串的地址移动到bx:
后调用它print_function:
pusha
mov ah, 0x0e
mov al, [bx]
int 0x10
cmp al, 0
jne increment
jmp the_end
increment:
add bx , 1
mov al, [bx]
int 0x10
cmp al, 0
jne increment
jmp the_end
the_end:
popa
ret