从引导扇区打印字符串仅显示第一个字符

时间:2016-04-25 17:58:46

标签: assembly bootloader bios bochs x86-16

我正在开发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"

2 个答案:

答案 0 :(得分:3)

将注册10H设置为AHINT 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