Hello World bootloader无法正常工作

时间:2010-04-13 15:34:57

标签: assembly x86 bootstrapping bootloader

我一直在完成教程on this webpage,它逐步创建一个显示Hello World的引导加载程序。

第二个教程(我们尝试输出“A”)可以很好地工作,但是第一个教程对我来说根本不起作用! (BIOS完全忽略了软盘并直接启动进入Windows)。这不是一个问题,但任何解释都会受到赞赏。

真正的问题是我无法获得第3个教程。而不是输出“Hello World”,我在屏幕的左下角得到一个不寻常的字符(和闪烁的光标)。它看起来有点像圆角矩形内的笑脸。有谁知道如何让Hello World显示它应该显示?

2 个答案:

答案 0 :(得分:7)

你说“直接启动进入Windows”,所以我假设你使用的是物理PC。未来的注意事项:始终使用模拟器进行开发!这更容易。我喜欢Bochs for OSDeving,因为它有很好的调试功能。现在,了解可能的解决方案。

有很多错误的BIOS会破坏IBM PC的非正式规范,以获取0x7C00加载地址。

这可能会给你的内存地址带来很多问题。所以开头看起来像这样:

[BITS 16] ;tell the assembler that its a 16 bit code
[ORG 0x7C00] ;this tells the assembler where the code will be loaded at when it runs on your machine. It uses this to compute the absolute addresses of labels and such.

jmp word 0:flush ;#FAR jump so that you set CS to 0. (the first argument is what segment to jump to. The argument(after the `:`) is what offset to jump to)
;# Without the far jmp, CS could be `0x7C0` or something similar, which will means that where the assembler thinks the code is loaded and where your computer loaded the code is different. Which in turn messes up the absolute addresses of labels.
flush: ;#We go to here, but we do it ABSOLUTE. So with this, we can reset the segment and offset of where our code is loaded.
mov BP,0 ;#use BP as a temp register
mov DS,BP ;#can not assign segment registers a literal number. You have to assign to a register first.
mov ES,BP ;#do the same here too
;#without setting DS and ES, they could have been loaded with the old 0x7C0, which would mess up absolute address calculations for data. 

请参阅0x07C0:0000处的某些负载和0x0000:7C00处的大部分负载(以及其认为合适的负载)。它是相同的平坦地址,但不同的段设置实际上可以搞砸绝对内存地址。所以让我们删除汇编程序的“魔力”并查看它的外观(注意我不保证地址完全正确。我不知道所有操作码的大小)

jmp word 0:0x7C04 ;# 0x7C04 is the address of the `flush` label 
...

所以,我们跳到绝对地址。

现在。当我们不这样做时会发生什么?

以此程序为例:

mov ax,[mydata]
hlt

mydata: dw 500 ;#just some data

这反汇编到像

这样的东西
mov ax,[0x7C06] 

哦,它使用绝对寻址,那怎么会出错呢?那么,如果DS实际上是0x7C0怎么办?然后,不是让预期的汇编程序0:0x7C06得到0x7C0:0x7C06,而是相同的扁平地址。

我希望这可以帮助你理解。这确实是一个复杂的主题,需要一段时间的低级编程才能完全理解。

答案 1 :(得分:1)

我认为问题很可能与指定的来源有关。

[ORG 0x7C00]    ;Origin, tell the assembler that where the code will

根据我们一直有的对话,看来地址不是以某种方式预测的。可能只是DS数据段寄存器不是您所期望的。实际上,您可以通过在调用之前添加一个ds的push和pop来获取网页上的原始列表,以显示这样的字符串,

 push cs
 pop ds

如果不是,则以下代码有效。

 [ORG 0x000]    ; switched to 0 since we are going to try to correct it ourself

 call nextinstruction
 nextinstruction:    ; get the return address of the call into dx
 pop dx              ; which is essentially the start of the code + 3 (3 bytes for the call instruction)
 MOV SI, HelloString ;Store string pointer to SI
 add si, dx          ; add IP from start of program
 sub si, 3           ; subtract the 3 the call instruction probably took
 push cs
 pop ds              ; make ds the same as cs.  
 CALL PrintString   ;Call print string procedure
 JMP $      ;Infinite loop, hang it here.

此代码计算出正在运行的代码的运行时偏移量,并确保DS指向同一段。除非另有说明,否则涉及SI的指令通常也使用DS作为其代码段来引用内存。

DS是一个细分受众群注册,您可能需要阅读Art of Assembly之类的内容以了解详情。

Earlz也在做同样的事情,只是确保寄存器正确,以便正确引用内存地址。只是他比我更了解引导扇区的细节。