I decided to teach myself assembly language.
セグメント レジスタの値を変更しようとすると、プログラムがコンパイルされないことに気付きました。
私が見つけたすべての記事は、実際に少なくとも 4 つのセグメント レジスタの値を変更できると述べています。
この時点で本当に興味があるのはその理由だけです。これらのアドレスを変更する本当の目的はありません。
あなたはその理由に興味があると言ったので、
リアル モードでは、セグメントは物理メモリに対する 64K の "ウィンドウ" であり、これらのウィンドウは 16 バイト間隔で配置されます。保護モードでは、セグメントは物理メモリまたは仮想メモリへのウィンドウであり、そのサイズと場所は OS によって決定され、プロセスがアクセスするために必要な特権レベルなど、他の多くのプロパティがあります。
ここから先、私が言うことはすべて保護モードについて言及します。
グローバル記述子テーブル (GDT) と呼ばれるメモリ内のテーブルがあります。ここには、これらのウィンドウのサイズと場所、およびその他のプロパティに関する情報が保持されます。プロセスごとにローカル記述子テーブルが存在する場合もあり、それらは同様に機能するため、GDT に焦点を当てます。
セグメント レジスタにロードする値は、セグメント セレクターと呼ばれます。これは、GDT または LDT へのインデックスであり、追加のセキュリティ情報が少し含まれています。当然、プログラムが GDT の境界外にある記述子をロードしようとすると、例外が発生します。また、プロセスがセグメントにアクセスするための十分な特権を持っていない場合、または何かが無効な場合、例外が発生します。
例外が発生すると、カーネルがそれを処理します。この種の例外は、おそらくセグメンテーション違反として分類されます。したがって、OS はプログラムを強制終了します。
最後に注意点が 1 つあります。x86 命令セットでは、即値をセグメント レジスタにロードすることはできません。中間レジスタ、メモリ オペランド、またはセグメント レジスタへの POP を使用する必要があります。
MOV DS, 160 ;無効 - アセンブルしません MOV AX, 160 ; VALID - アセンブルしますが、おそらく MOV DS、AX ;例外、したがってプログラムの終了
アーキテクチャがセグメントのヒープを許可していることを指摘する必要があると思います。しかし、私の知る限り、メインストリームの x86 オペレーティング システムに関して言えば、セグメント レジスタはいくつかの目的しか果たしません。
TLS のスレッドごとのセグメントとは別に、実際にはほんの一握りのセグメント (プロセッサの数倍) だけが、OS によってのみ使用されます。アプリケーション プログラムは、セグメント レジスタを完全に無視できます。
これは OS の設計によるものであり、技術的な制限によるものではありません。私は知りませんが、セグメントレジスタを操作するためにユーザー空間プログラムを必要とする組み込みオペレーティングシステムがあるかもしれません。
Windows 実行可能ファイルを作成していますか?
プロテクト モード (Win32) では、セグメント レジスタは使用されなくなりました。
参考:
メモリモデルも昔の16ビット世界とは大きく異なります。Win32 では、メモリ モデルやセグメントを気にする必要はもうありません。メモリ モデルは 1 つだけです。フラット メモリ モデルです。もう 64K セグメントはありません。メモリは4GBの大連続空間。これは、セグメント レジスタをいじる必要がないことも意味します。任意のセグメント レジスタを使用して、メモリ空間内の任意のポイントをアドレス指定できます。これは、プログラマーにとって大きな助けになります。これにより、Win32 アセンブリ プログラミングが C と同じくらい簡単になります。