我正在尝试编写自己的Os,我需要一些print_string func,它将在sI中打印字符串就像这样
print_string:
Pusha
mov ah,0Eh
.repeat:
lodsb
cmp al,0
je .done
int 10h
Jmp .repeat
.done:
Popa
Ret
但输出
mov si,Msg
call print_string
就像Wn = Wn =
而Msg是"你好"
答案 0 :(得分:1)
这不是一个最小的完整示例,但问题很常见。即使没有看到其余的代码,我猜你在启动时处理器(或模拟处理器)使用的段中存在不匹配,并且汇编代码使用了偏移量。
对于16位segment:offset addressing,有许多段和偏移的组合指向相同的物理内存地址。 BIOS使用的最常见的是0x07c0:0x0000和0x0000:0x0000。 (0x07c0&lt;&lt; 4)+ 0x0000 =物理地址0x07c00。 (0x0000 <&lt;&lt; 4)+ 0x7c00 =物理地址0x07c00。我们的想法是,您希望ORG指令反映您要使用的偏移部分,然后在启动引导程序时手动设置 DS 。 NASM中缺少ORG指令(使用-f bin
构建时)默认为org 0x0000
。
我有一般的Bootloader提示说:
- 当BIOS跳转到您的代码时,您不能依赖 CS , DS , ES , SS , SP 寄存器具有有效或预期的值。应在引导加载程序启动时正确设置它们。您只能保证从物理地址0x00007c00加载并运行引导加载程序,并将引导驱动器号加载到 DL 寄存器中。 [剪断]
- 可以设置或清除
lodsb
,movsb
等使用的方向标记。如果方向标志设置不正确 SI / DI 寄存器可能会以错误的方向调整。使用STD
/CLD
将其设置为您希望的方向(CLD =向前/ STD =向后)。在这种情况下,代码假定向前移动,因此应使用CLD
。有关详细信息,请参阅instruction set reference
当引导加载程序启动时,您不能依赖DF标志(LODSB所需)和段寄存器(如 DS )作为特定值(或右侧)。您需要在代码的开头明确设置它。如果不这样做,您要打印的字符串将从RAM的错误部分读取,结果将是乱码。您似乎两次打印相同的乱码的事实表明另一个问题,那就是您没有某种无限循环来结束您的引导加载程序。我还有另一个Stackoverflow Answer我认为是相关的。
我将填写一个缺少的引导加载程序,它调用您提供的print_string
函数,该函数使用0x0000作为段,我们使用org 0x7c00
作为起始偏移量:
; Create bootloader with: nasm -f bin boot.asm -o boot.bin
; To test in QEMU use: qemu-system-i386 -fda boot.bin
org 0x7c00
main:
xor ax, ax ; XOR register with itself zeroes the register
mov ds, ax ; We want DS:ORG to be 0x0000:0x7c00
cld ; Forward direction for string instructions like LODSB
mov si,Msg
call print_string ; Print the message
; This is a preferred way to do an infinite loop but
; you could also do: JMP $. This prevents falling through
; the code below and off to memory we don't intend to execute
cli
.endloop:
hlt
loop .endloop
print_string:
Pusha
mov ah,0Eh
xor bx,bx ; Ensure we are writing to page 0
; XOR register with itself zeroes the register
.repeat:
lodsb
cmp al,0
je .done
int 10h
Jmp .repeat
.done:
Popa
Ret
; Place data after the code but before the boot signature.
Msg db "hello",0 ; Nul terminated string
times 510 - ($ - $$) db 0 ; padding with 0 at the end
dw 0xAA55 ; PC boot signature
或者我们可以使用一段0x07c0并使用org 0x0000
(或省略它),它仍然可以工作。代码的开头可能如下所示:
org 0x0000
main:
mov ax, 0x07c0
mov ds, ax ; We want DS:ORG to be 0x07c0:0x0000
cld ; Forward direction for string instructions like LODSB
这是我使用QEMU获得的两个版本的输出: