在VMWare和Bochs上运行操作系统引导加载程序时遇到问题。
引导加载程序应该通过int 10h
显示一个字符串,但它只打印没有任何字符的背景颜色。
颜色由bx
的值设定。代码在这里:
org 7c00h
; org 0100h
mov ax, cs
mov ds, ax
mov es, ax
call DispStr
jmp $
DispStr:
mov ax, BootMessage
mov bp, ax
mov cx, 13
mov ax, 1301h
mov bx, 005eh
mov dh, 3
mov dl, 0
int 10h
ret
BootMessage: db "Hello, Luser!"
times 510-($-$$) db 0
dw 0xaa55
答案 0 :(得分:1)
虽然这个答案很晚,但问题很简单,代码是开发人员的一个很好的例子,假设BIOS跳转到具有有效或预期值的代码。我最近回答了一些关于 bootloaders 的问题,并开始提供general tips。提示#1应适用于此处:
由于您正在进行BIOS int
调用,因此应确保设置自己的堆栈。您不能保证 SS / SP 指向足够的堆栈空间,或者当BIOS跳转到物理内存地址0x00007C00
的代码时甚至有效。唯一的要求是BIOS开始在该位置执行代码,但它没有说明应该使用 CS 和 IP 来执行此操作。 BIOS还将通过DL
中的启动驱动器。
许多不同的segment:offset对可以引用单个物理内存位置。例如,这些都指向引导加载程序物理地址:
0x0000:0x7C00 = (0x0000<<4)+0x7C00 = 0x00007C00
0x0203:0x5BD0 = (0x0203<<4)+0x5BD0 = 0x00007C00
0x07C0:0x0000 = (0x07C0<<4)+0x0000 = 0x00007C00
正如您所看到的,上面的示例让您了解使用segment:offset对解决单个内存位置的方法不止一种。海报提供的代码假定 CS 段将为0
。可以观察代码中的org 7c00h
,它表示当编译器生成目标文件时,所有绝对近存储器引用都会被0x7C00
偏移。由于我们将在0x7C00
内存加载到内存中,因此我们的 DS 必须为0x000
。
这与OP的代码有何关系。注意我们从:
开始mov ax, cs
mov ds, ax
mov es, ax
我们盲目地移动 CS 中的内容并将其传输到 DS 和 ES 。我们的代码特别需要0x0000
的 DS 才能正常工作(来源0x7C00
)。我给出了一些映射到物理位置0x7C00
的 CS:IP 对的示例。如果BIOS专门通过远程跳转跳转到我们的代码0x0000:0x7C00
,我们的 CS 将是0x0000
和 IP 将是0x7C00
。如果我们将0x0000
移至 DS 和 ES ,一切都会好的。如果BIOS 远远跳转到0x07C0:0x0000会发生什么?我们的 CS 中包含0x07C0
, IP 将为0x0000
。如果我们将 CS 移动到 ES 和 DS ,所有这些段都是0x07C0
,但我们编写的代码相对于{{{ 1}}。
错误的段可能会出错?假设汇编程序将0x0000
置于偏移Bootmessage
(0x50 + 0x7C00原点)。现在执行以下代码:
0x7C50
由于没有指定任何段,因此它与说mov ax, BootMessage
相同。如果我们的 DS 段设置为DS:BootMessage
且0x07C0
设置为Bootmessage
,那么我们就会访问物理地址(0x07C0&lt;&lt;&lt; 4)+ 0x7C50 = { {1}}。现在应该很明显 - 如果 CS 不是0,我们将从我们的字符串不存在的内存地址加载 BootMessage 。
要解决这个问题很简单。不要认为 CS 是我们所期望的。对引导加载程序进行编码以使用我们想要的内容。我们打算将 DS 和 ES 设置为细分0x7C50
:
0xF850
使用0x0000
和其他一些使用xor ax, ax ; Set AX to 0
mov ds, ax ; Initialize DS=ES=0
mov es, ax
的其他人知道远jmp 到我们的引导加载程序的一些虚拟机和真实硬件。如果您认为 CS 中的值是您想要的,那么您的代码可能在某些平台上运行,而不是在其他平台上运行。