5

私はこのWebページのチュートリアルを進めてきました。このチュートリアルでは、HelloWorldを表示するブートローダーが徐々に作成されます。

2番目のチュートリアル(「A」を出力しようとする)は完全に機能しますが、1番目のチュートリアルはまったく機能しません。(BIOSはフロッピーディスクを完全に無視し、Windowsを直接起動します)。説明をいただければ幸いですが、これはそれほど問題ではありません。

本当の問題は、3番目のチュートリアルを機能させることができないことです。「HelloWorld」を出力すると、画面の左下隅に異常な文字(およびカーソルの点滅)が表示されます。丸みを帯びた長方形の中のスマイリーフェイスのように見えます。Hello Worldを表示する方法を知っている人はいますか?

4

2 に答える 2

7

「Windows を直接起動する」と言うので、物理 PC を使用していると思います。今後の注意事項: 開発には常にエミュレーターを使用してください。それはただ簡単です。私は Bochs for OSDeving が好きです。なぜなら、Bochs には優れたデバッグ機能があるからです。さて、可能な解決策に。

0x7C00 ロード アドレスの IBM PC の非公式仕様を破るバグのある BIOS がたくさんあります。

これにより、アセンブル中はいつでもメモリアドレスなどに多くの問題が発生する可能性があります。したがって、冒頭を次のようにします。

[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-13T16:44:37.580 に答える
1

問題は指定された起源に関連している可能性が高いと思います。

[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はセグメントレジスタであり、 ArtofAssemblyのようなものを読んで詳細を確認することをお勧めします。

Earlzも同じようなことをしていますが、メモリアドレスが正しく参照されるように、レジスタが正しいことを確認するだけです。彼は私よりもブートセクターの詳細についてよく知っているだけです。

于 2010-04-13T15:48:49.900 に答える