我一直在学习教程on this webpage,它逐步创建了一个显示Hello World的引导加载器。
第二个教程(我们试图得到一个"A“作为输出)工作得很好,但是第一个教程对我来说根本不起作用!( BIOS完全忽略软盘,直接引导至Windows)。这不是一个问题,尽管任何解释都会受到欢迎。
真正的问题是我不能让第三个教程工作。相反,在输出"Hello World“时,我在屏幕的左下角看到一个不寻常的字符(和闪烁的光标)。它看起来有点像一个圆角矩形里面的笑脸。有谁知道如何让Hello World像它应该显示的那样显示吗?
发布于 2010-04-14 00:44:38
你说“直接启动进入windows”,所以我假设你使用的是一台物理PC。未来要注意的是:始终使用模拟器进行开发!这样更容易。我喜欢Bochs for OSDeving,因为它有很好的调试功能。现在,来看看可能的解决方案。
有很多错误的BIOSes破坏了IBM对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,它们是,而不是,相同的平面地址。
我希望这能帮助你理解。这确实是一个复杂的主题,需要一段时间的低级编程才能完全理解。
发布于 2010-04-13 23:48:50
我认为这个问题很可能与指定的来源有关。
[ORG 0x7C00] ;Origin, tell the assembler that where the code will根据我们一直在进行的对话,这个地址似乎在某种程度上并不像预测的那样。可能只是DS数据段寄存器不是您所期望的。实际上,您可以通过在调用前添加ds的推送和弹出来显示字符串,从而使web页面中的原始列表生效。
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也在做同样的事情,只是确保寄存器是正确的,以便正确引用内存地址。只是他比我更了解启动扇区的细节。
https://stackoverflow.com/questions/2630899
复制相似问题