わからない。マニュアルは技術的すぎます。フラットメモリとセグメントメモリとは何ですか?メモリをアドレス指定する方法、メモリ内のバイトを編成する方法は?32ビットコンピュータに最適なのはどれですか?誰か説明できますか?リアルモードとプロテクトモードは、フラットメモリまたはセグメント化メモリと何の関係がありますか?ありがとう!
2 に答える
既存の32/64ビットオペレーティングシステムで実行されているアプリケーションのみに関心がある場合は、セグメント化されたメモリを忘れることができます。32ビットOSでは、4GBの「フラット」メモリスペースがあると想定できます。フラットとは、予想どおり、32ビット値とレジスタを使用してアドレスを操作できることを意味します。
16ビットプロセッサでは、アドレスは20ビット幅で、レジスタに格納できないと思います。そのため、1つのレジスタにベースを格納し、実際のアドレスを指定するには、にオフセットを追加する必要がありました。そのベース。(私が正しく覚えていれば、ベースに16を掛けてから、オフセットを追加して実際のアドレスを取得しました。)これは、一度に64KBしかアドレス指定できないことを意味します。メモリは64KBブロックに「セグメント化」する必要がありました。
正直なところ、初心者がまだそれについて聞いている唯一の理由は、古い16ビットのチュートリアルや本がまだたくさんあるからだと思います。プログラムがアセンブリレベルでどのように機能するかを理解する必要はありません。さて、OS開発を学びたいのなら、それは別の話です。PCは16ビットモードで起動するため、フラット32ビットモードをアクティブにできるように少なくとも十分に学習する必要があります。
リアルモードとプロテクトモードについても質問されていることに気づきました。リアルモードは、MSDOSが使用したモードです。どのプログラムもハードウェア機能にアクセスできました。たとえば、グラフィックカードのコントローラーに直接話しかけて何かを印刷するのが一般的でした。マルチタスクOSではなかったので問題ありませんでした。
しかし、最近のOSでは、通常のプログラムはハードウェアに直接アクセスせず、メモリにも直接アクセスしません。OSはハードウェアを管理し、プロセッサで実行するプロセスを決定します。また、すべてのプロセスの仮想アドレス空間を管理します。この種の機能はプロテクトモードで利用できます。プロテクトモードは、PC用の最初の32ビットプロセッサである386に付属していると思います。
アドレス(メモリ、I / O、メモリマップドI / Oなど)を使用して何かにアクセスする命令は、完全な(プロセッサ実行のその層の観点から)アドレスを提供する場合もあれば、オフセットを提供する場合もあります。たとえば、プログラムカウンターがベースアドレスであり、命令がそのベースへのオフセットを提供し、2つを足し合わせると、(そのレベルで)アドレスが取得されます。
16ビットレジスタと64Kバイトの最大アドレス空間制限がある16ビットシステムを考えてみましょう。そのメモリを拡張する非常に簡単な方法は、セグメント化することです。アドレス全体を含むレジスタの代わりに、命令のレジスタには、PC相対命令のように、ベースへのオフセットが含まれています。この場合を除いて、ベースアドレスとして使用されるさらに別のレジスタがあります。これは、コアに変更を加えなくてもアドレス範囲を簡単に拡張したいと考えていた多くのアーキテクチャで見られます。(コアを変更せずにメモリコントローラーで実行できます)x86の場合、いくつかのレジスタがありました。1つは、実行範囲を拡大するために使用されました。もう1つは、データアクセス、ロード、およびストアの範囲を拡張するためのものです。非PC相対分岐のアドレスは、左に4ビットシフトされたコードセグメントを使用して計算され、命令で指定されたレジスタに追加されました。PC相対ではないロードおよびストアの場合、データセグメントレジスタが使用されました。左にシフト4して、命令で指定されたレジスタを追加します。したがって、0x123456789をアドレス指定する場合は、セグメントレジスタに0x12340000を含め、アドレス指定に使用するレジスタに0x56789を含めるか、セグメント0x12345678とgprに0x9を含めることができます。PC相対アドレス指定は、もちろんセグメント+pc+オフセットです。したがって、0x123456789をアドレス指定する場合は、セグメントレジスタに0x12340000を含め、アドレス指定に使用するレジスタに0x56789を含めるか、セグメント0x12345678とgprに0x9を含めることができます。PC相対アドレス指定は、もちろんセグメント+pc+オフセットです。したがって、0x123456789をアドレス指定する場合は、セグメントレジスタに0x12340000を含め、アドレス指定に使用するレジスタに0x56789を含めるか、セグメント0x12345678とgprに0x9を含めることができます。PC相対アドレス指定は、もちろんセグメント+pc+オフセットです。
これにより、さまざまなメモリモデルが採用されました。小さい、小さい、中程度、大きい、大きい。最小のモデルにルールがあるか、x86の場合、すべてが64Kのメモリ空間内にあると想定できます。コンパイラとコードは、セグメントレジスタについて心配する必要はなく、固定されたままであると想定されます。より大きなモデルの場合、または遠くに到達する遠いポインタを使用することが大したことではない場合は、データセグメントを設定してから、データオフセットを設定し、ロードまたはストアを実行します。コードの場合、コードセグメントレジスタを変更するとすぐに、命令をフェッチするアドレス全体に影響するため、少し難しいと想像できます。ブランチがセグメントとオフセットの両方を変更できるようにするハードウェアソリューションが必要な場合もあれば、コードでそれを行うこともできます(ハードウェアが許可されている場合)。今のところ、それと混同することはありません。
コードに配列があるときはいつでも:
unsigned char abc[123];
それは基本的に同じです。ベースアドレス、つまり配列がメモリ内で開始するアドレスはセグメントのようなものであり、インデックスはオフセットです。上記でabcがアドレス0x1004にあった場合、abc[5]はアドレス0x1004+ 5=0x1009にあります。x86セグメント:オフセットアドレス指定のようにシフトされませんが、ベースとオフセットを追加するという同じ概念です。追加されていないセグメント化されたアーキテクチャの中には、レジスタのどこかにあるビットが上位ビットであるものもあります。これらのシステムの1つでアドレス0x12345を取得します。0x1はセグメントにあり、0x2345は16ビットgprにある必要があります。必要に応じてシフトおよび追加と考えることができますが、x86 segment:offsetとは異なり、シフトおよびまたはと考えることもできます。
フラットメモリスペースは、特にx86システムでは少し幻想です。x86コンピューター(32ビットおよび多くの64ビット)は、プラグインカードのフラットメモリスペースの量を合計1ギガに制限し、合計4ギガのアドレス空間がある32ビットシステムには非常に理にかなっています。これが、これらのいくつかが3ギガの制限を与えたり、4ギガの錯覚を与えたりする理由ですが、プラグインカード用にその一部を切り取っています。(マザーボード上のアイテムの多くは、実際のプラグインカードと同様にこのスペースにあります)。ビデオカードや解像度などによっては、フレームバッファ全体をその周辺空間のサブセットに収めることができない場合があるため、アクセスをセグメント化する必要があります。BIOSは、x86アドレス空間のベースとしてアドレス0x80000000を指定している可能性があります。次に、ビデオカードの他のレジスタで、ビデオカードのアドレス空間内のアドレスを指定します。デモンストレーションの目的で、x86アドレス0x80000000で16MByteウィンドウが与えられたとしましょう。16Mバイトは0x01000000です。ビデオメモリのアドレス0x04321888にアクセスする場合は、ビデオカードのセグメントレジスタを0x04に設定し、x86アドレス空間(pci(e)アドレス空間でもある)でアドレス0x80321888を使用する必要があることを想像できます。
ここで重要なのは、ここからいくつかのビットを取り、そこからいくつかのビットを取り、それらをまとめて、それがターゲットのアドレスです。ビデオカードやオンボードI/Oコントローラ、またはpciやpcieコントローラなどの周辺機器を扱う場合は、ターゲットのアドレス空間の観点から考えることを学ぶ必要があります。プロセッサには、プログラムの観点から見たアドレス空間があります。mmuはそれを物理アドレス空間にスクランブルすることができ、実際にスクランブルします。次に、pcieアドレス空間があり、pcieを介してアクセスされるペリフェラルには独自のアドレス空間があります。IntelとIntelベースのPCワールドが行ったことは、プロセッサの物理アドレス空間とPCIeアドレス空間を同じにすることです。mmuでの仮想スクランブリングと物理スクランブリングはまだ存在し、周辺機器のアドレス空間へのウィンドウはまだ存在します。
本当の保護されたものはアクセスと関係があります。たとえばCでは、ポインタを作成したり、ポインタを変更したり、必要なアドレスを作成したりできます。これは、別のアプリケーションメモリやカーネルのメモリを調べられることを意味しませんか?理想的には、それを起こさせたくないので、そのアプリケーションの命令を実行しているときに、仮想マシンのビットにいるアプリケーションごとに、コードや命令のすべてのメモリアクセスは、必要に応じてフィルターを通過します。そのフィルターは、そのアクセスがプログラムの許可されたスペース内にあるかどうかを確認します。そのスペースの外に出ると、例外が発生し(割り込みを考えます)、その例外により、カーネル(これらの制限がないか、異なる制限がある)がそのアクセスを許可するかどうかを決定できます。 、またはおそらく何かへのアクセスを仮想化して、または、ユーザーに警告を発します(一般保護違反)。たとえば、vmwareのような実際の仮想マシンプログラムを取り上げ、仮想化プログラムがプロセッサ上で実際に命令を実行できるようにします。その仮想化プログラムがビデオカードのアドレスであると見なすものにアクセスすると、保護障害が発生し、vmwareドライバ/アプリケーション(カーネルレベルと考えてください)は、そのアドレスを取得し、ビデオカードの応答を偽造して、アプリケーションに制御を戻します。命令をメタル上で実行させることで、すべてのプロセッサ命令をシミュレートするという代替手段よりもはるかに高速な仮想化が可能になります。これは極端なケースです。これを読んでいるWebブラウザーでさえ仮想化されているため、0x000や0x8000などのベースアドレスに基づくメモリスペースがあると見なされます。特定のOSの各プログラムを同じフラットな仮想メモリ空間にコンパイルすると、オペレーティングシステムがアドレスを仮想から物理に変更します。そのアドレス0x8000へのWebブラウザアクセスは物理0x12345678である可能性があり、mp3プレーヤープログラム0x8000アクセスは物理0x2345678である可能性がありますが、両方のアプリケーションに対して、それらの命令は0x8000を計算しています。
何が最善かを尋ねることは常に相対的な用語であり、ある人が最も良い人は別の人が最も悪い人です。あなたは自分自身のために最悪から最高を定義する必要があります。勢いと世論がx86をフラットなメモリ空間に追いやったか、少なくともプログラマーの観点からはフラットなメモリ空間の幻想に駆り立てられたので、フローを進めるのに問題が少なくなります。
8086/8088プログラマーとハードウェアリファレンスマニュアルのコピーを入手することをお勧めします。1つは数ドルで手に入れることができます。
pcemuのようなシミュレーターを取ります(私はこの目的のためのクローンを持っていますhttp://github.com/dwelch67/pcemu_samples)そして、仮想化、保護などのかなり前の古い学校の命令セットで遊んでください。上記のようにセグメントとオフセットを計算したときに、セグメントを左に4つシフトし、オフセットを追加します(これはすべてこのマニュアルで説明されています)。それ以来、すべての世代は、下位互換性を確保しようとしながら、改善を試みるために何かを行ってきました。これはもちろん利益を助けましたが、プロセッサを厄介な獣に変えました。x86の詳細を忘れて、よりクリーンなシステムを学ぶことをお勧めします。x86がどのように進化したかによって、たとえば、コンパイルされたコードよりもasmで何かを書き込もうとするなどのメリットは最小限に抑えられます。異なるファミリのプロセッサが異なる速度で同じコードを実行するため、多くの場合、新世代は以前の手動で調整されたコードをはるかに遅い速度で実行します。すべてのプラットフォームで高速になるように手動で調整することはできません。コンパイラが高速にすることはできないため、x86asmコードをコンパイラに任せてください。これらの問題がなく、必要に応じて調整したり、より優れたコンパイラを作成したりできる、正常なプラットフォームで作業してください。