アセンブラは、ソースコードの各行をプロセッサ命令に変換し、これらの命令を次々に出力バイナリファイルに生成します。そうすることで、0から上に向かってそのような命令の現在のアドレスをカウントする内部カウンターを維持します。
通常のプログラムをアセンブルしている場合、これらの命令は、アドレス用の空白のスロットがあるオブジェクトファイルのコードセクションに表示されます。このスロットには、後でリンカによって適切なアドレスを入力する必要があるため、問題ありません。
ただし、セクション、再配置、その他のフォーマットを使用せずに、生のマシン命令だけでフラットバイナリファイルをアセンブルする場合、ラベルがどこに表示され、コードとデータのアドレスが何であるかについてのアセンブラの情報はありません。したがって、たとえば、命令があるmov si, someLabel
場合、アセンブラは、バイナリファイルの先頭の0から始まるこのラベルのオフセットのみを計算できます。(つまり、デフォルトはORG 0
指定しない場合です。)
それが正しくなく、メモリ内のマシン命令+データを他のアドレスから開始する場合、たとえば、プログラムの開始アドレスがソースの先頭に書き込むことによって7C00
アセンブラに通知する必要があります。このディレクティブは、アセンブラに、内部アドレスカウンタをからではなくから起動する必要があることを通知します。その結果、そのようなプログラムで使用されるすべてのアドレスが。だけシフトされます。アセンブラは、ラベルごとに計算された各アドレスに単純に追加します。その効果は、ラベルがメモリ内のアドレスに配置されているかのようになります。たとえば、()だけでなく( )7C00
org 0x7C00
7C00
0
7C00
7C00
7C48
7C00 + 48
0048
0000 + 48
)、バイナリイメージファイルの先頭から48バイトだけオフセットされているかどうかに関係なく(オフセットでロードした後7C00
、適切なアドレスが提供されます)。
これらの「アドレス」は、jmp si
またはのように直接使用される場合、論理アドレス指定mov al, [si]
のoffset
一部であり、リアルモードでは、セグメント部分が4だけ左シフトされ、オフセットが追加されるベースを取得します。(したがって、同じ線形アドレスをアドレス指定します。)この部分は、関連するセグメントレジスタに入力したもの、または固定値に設定しなかった場合はBIOSがそこに残したものに由来します。seg:off
07C0:000
0000:7C00
7C00
segment
、、、および/またはセグメントレジスタが線形アドレス空間のどこにMBRがロードされるか(常に)に一致するように設定されている場合cs
、ファイルの最初のバイトは、たとえば、正しく設定されたセグメントベースでそのオフセットを使用すると実際にデータに到達します。 が設定されている場合は、そのラベルにジャンプします。コードがある場所です。つまり、MBRの最初のバイトを参照する場合。 が正しく設定されている場合、そこから2バイトがロードされます。ds
es
7C00
es:0
jmp si
cs
cs:si
cs:org
mov ax, [si]
ds
あなたの場合、int 10h
/ah=13h
はをes:bp
使用し、絶対アドレス指定の他の使用法はなく、エンコーディングがに依存しない相対ジャンプ/呼び出しのみorg
です。使用しているものに一致するように固定値に設定するのではなく、何らかの理由でブートローダーの開始時に設定しes
ます。これはバグです。ブートローダーは、CS:IP =でMBRにジャンプするBIOSでは機能せず、一致するBIOSのみを使用します。;に置き換えてこれを修正します。DS / ESがCSと異なるかどうかは関係ありません。それだけで、データが実際に存在します。cs
org
07C0:0000
0000:7C00
org
mov ax,cs
xor ax,ax
ES: BootMessage-$$ + org
線形アドレスと論理アドレス
あなたの他の質問に関して:7C00
ブートローダーの線形物理アドレスです。セグメントがオーバーラップするため、この物理アドレスを論理アドレス(segment:offset)としてさまざまな方法で表すことができます(次のセグメントは10
前のセグメントの後に16バイト(16進数)で始まります)。たとえば、最も単純な構成である論理アドレスを使用できます。RAMの先頭から始まる0000:7C00
セグメントを使用し、そこからオフセットします。または、 thセグメントである論理アドレスを使用できます。セグメントは互いに16バイト離れて開始することを覚えていますか?したがって、これに(10進数で)を掛けると、次のようになります。0
7C00
0
07C0:0000
7C0
7C0
10
16
7C00
- 見る?16進アドレスの1つ右にシフトするだけです。:-)ここで、オフセットを追加するだけです。これは0
今回なので、7C00
物理的にはまだです。メモリ内で始まる0
セグメント内のバイト。07C0
7C00
もちろん、たとえば、のようなより複雑なアドレスを使用することもできます0234:58C0
。これは、セグメントがで始まり、それにオフセットを2340
追加すると、再び取得されることを意味します:-)しかし、それを行うと混乱する可能性があります。それはすべて、必要な構成によって異なります。物理アドレスをセグメントの開始と見なす場合は、セグメントを使用するだけで、最初の命令がオフセットになるため、ディレクティブを配置する必要はありません。または、配置することができます。ただし、アドレスの下のデータの読み取り/書き込みが必要な場合(たとえば、BIOSデータをのぞいたり、割り込みベクトルをいじったりする場合)、セグメントとオフセットを使用します。58C0
7C00
7C00
07C0
0
org
org 0
7C00
0
7C00
これは、最初の命令(バイナリファイルの0番目のバイト)が7C00
メモリ内の物理アドレスに配置されることを意味します。org 0x7C00
次に、上記の理由からディレクティブを追加する必要があります。
BIOSは、CS:IP = 07C0:0000または0000:7C00のコードにジャンプします。また、DS / ES / SS:SPの値が不明です。xor ax,ax
を使用している場合は、 /mov ds,ax
を使用してDSベースをゼロに設定し、どちらの方法でも機能するようにブートローダーを作成する必要がありますorg 0x7c00
。
すべてのBIOSが主流のソフトウェアで正しく動作する必要がある場合を除いて、BIOSが残した状態についての仮定を回避する堅牢なブートローダーの作成について詳しくは、MichaelPetchのブートローダー開発に関する一般的なヒントを参照してください。(たとえば、線形アドレス0x00007c00で512バイトのMBRをロードし、DLでドライブ番号をロードします)。
ほとんど(?)すべてのBIOSは、CS=0またはCS=07C0のいずれかでMBRを開始しますが、同じ線形アドレスに到達する他のseg:off方法ではありません。しかし、あなたは間違いなくどちらかを想定するべきではありません。