您说“直接启动到 Windows”,所以我假设您使用的是物理 PC。未来注意事项:始终使用模拟器进行开发!这更容易。我喜欢用于 OSDeving 的 Bochs,因为它具有很好的调试功能。现在,讨论可能的解决方案。
有很多错误的 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 呢?然后得到 0x7C0:0x7C06 而不是得到预期的汇编器 0:0x7C06 ,它们 不是 相同的平面地址。
我希望这可以帮助您理解。不过,这确实是一个复杂的话题,需要一段时间的低级编程才能完全理解。