1

作为学习操作系统开发的一部分,我正在 x86 引导扇区中开发代码。我希望我的代码将其打印到控制台:

你好

我得到了这个:

H

为什么它只打印一个字符而不是整个字符串?我怎样才能解决这个问题?

这是我的代码片段:

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"
4

2 回答 2

4

中断10H,寄存器AH设置为0EHINT 10h/AH=0eh),将打印寄存器中的当前字符AL。Ralf Brown 的中断列表被认为是 DOS 和 BIOS 中断的圣经。它是关于哪些中断可用、它们如何工作以及它们的副作用的宝贵信息来源。

如果您使用INT 10h/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 段可以被段覆盖前缀覆盖。

于 2016-04-25T18:05:35.560 回答
0

这已经很晚了,但可能会对某人有所帮助。我在 ubuntu 上开发操作系统时遇到了同样的问题。这对我有用。我创建了一个打印函数并在将我的字符串地址移动到 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
于 2018-03-20T16:24:05.520 回答