GNU/Linux >> Linux の 問題 >  >> Linux

セグメンテーション レジスタの使用

<オール>
  • リアルモードのプログラムを作成する人がいないので、かなり古い本を読んだに違いありません。 もう;-) リアルモードphyical address = segment register * 0x10 + offset でメモリアクセスの物理アドレスを取得できます オフセットは、汎用レジスタの 1 つの内部の値です。これらのレジスタは 16 ビット幅であるため、セグメントの長さは 64kb になり、属性がないという理由だけで、そのサイズについてできることは何もありません! * 0x10 で 乗算、1 MB のメモリが使用可能になりますが、セグメント レジスタに何を入れるかによって、重複する組み合わせがあります。 およびアドレス レジスタ . リアルモード用のコードをコンパイルしていません 、しかし、セグメントレジスタをセットアップするのはOS次第だと思います ELFバイナリをロードするときにローダーがいくつかのページを割り当てるのと同じように、バイナリのロード中に。ただし、ベアメタル カーネル コードをコンパイルしたので、これらのレジスタを自分でセットアップする必要がありました。

  • アーキテクチャの制約により、フラット モデルでは 4 つのセグメントが必須です。 保護モード セグメント レジスタ セグメント ベース アドレスは含まれなくなりましたが、セグメント セレクタ これは基本的に GDT へのオフセットです。 セグメント セレクターの値に応じて 、CPU は特定の特権レベルになります。これが CPL (現在の特権レベル) です。 セグメント セレクター セグメント記述子を指します これには DPL (記述子特権レベル) があり、セグメント レジスタ の場合、最終的に CPL になります。 このセレクターで埋められます (少なくともコードセグメントセレクターには当てはまります)。したがって、少なくとも 1 組の セグメント セレクター が必要です。 カーネルをユーザーランドと区別するため。さらに、セグメントはコード セグメントまたはデータ セグメントのいずれかであるため、最終的に 4 つの セグメント記述子 になります。

  • 下位互換性のためにセグメンテーションがまだ存在しているという理由だけで、セグメンテーションを使用する本格的な OS の例はありません。フラット モデル アプローチを使用することは、それを取り除くための手段にすぎません。とにかく、その通りです。ページングは​​はるかに効率的で用途が広く、ほぼすべてのアーキテクチャ (少なくとも概念) で利用できます。ここでページングの内部を説明することはできませんが、知っておく必要があるすべての情報は、優れた Intel man:Intel® 64 and IA-32 ArchitecturesSoftware Developer's ManualVolume 3A:System Programming Guide, Part 1 にあります。


  • 質問 3 に対する Benoit の回答を拡張します...

    コード、定数データ、変更可能なデータ、スタックなどの論理部分へのプログラムの分割は、さまざまな時点でさまざまなエージェントによって行われます。

    まず、コンパイラ (およびリンカー) は、この区分が指定された実行可能ファイルを作成します。いくつかの実行可能ファイル形式 (PE、ELF など) を見ると、それらがある種のセクションやセグメント、または任意の名前をサポートしていることがわかります。ファイル内のアドレス、サイズ、場所に加えて、これらのセクションには、OS にこれらのセクションの目的を伝える属性があります。このセクションにはコードが含まれます (ここにエントリ ポイントがあります)、これ - 初期化された定数データ、それ - 初期化されていないデータ (通常はファイル内のスペースを取りません)、ここにスタックに関するもの、その上に依存関係 (DLL など) のリストがあります。など

    次に、OS がプログラムの実行を開始すると、ファイルを解析して、プログラムに必要なメモリ量、各セクションのどこに、どのようなメモリ保護が必要かを確認します。後者は通常、ページ テーブルを介して行われます。コード ページは実行可能かつ読み取り専用としてマークされ、定数データ ページは実行可能ではなく読み取り専用としてマークされ、他のデータ ページ (スタックのデータ ページを含む) は実行可能ではなく読み取り/書き込みとしてマークされます。これが本来あるべき姿です。

    多くの場合、プログラムは読み書き可能であると同時に、動的に生成されたコード用の実行可能領域、または単に既存のコードを変更できるようにする必要があります。組み合わされた RWX アクセスは、実行可能ファイルで指定するか、実行時に要求することができます。

    動的スタック拡張用のガード ページなど、他の特別なページが存在する場合があり、それらはスタック ページの隣に配置されます。たとえば、プログラムは 64KB のスタックに十分な数のページが割り当てられた状態で開始し、プログラムがそのポイントを超えてアクセスしようとすると、OS はそれらのガード ページへのアクセスをインターセプトし、スタックに追加のページを (サポートされている最大サイズまで) 割り当てて、ガードページをさらに移動します。これらのページは、実行可能ファイルで指定する必要はなく、OS が独自に処理できます。ファイルは、スタック サイズとおそらく場所のみを指定する必要があります。

    OS にコード メモリとデータ メモリを区別するためのハードウェアまたはコードがない場合、またはメモリ アクセス権を強制するための分割は非常に形式的です。 16 ビットのリアルモード DOS プログラム (COM および EXE) には、特別な方法でマークされたコード、データ、およびスタック セグメントがありませんでした。 COM プログラムは 1 つの共通の 64KB セグメントにすべてを持ち、IP=0x100 と SP=0xFFxx で始まり、コードとデータの順序は内部で任意であり、事実上自由に絡み合うことができました。 DOS EXE ファイルは、CS:IP および SS:SP の開始位置のみを指定し、それ以降はコード、データ、およびスタック セグメントを DOS と区別できませんでした。ファイルをロードし、再配置を実行し (EXE のみ)、PSP (コマンド ライン パラメータとその他の制御情報を含むプログラム セグメント プレフィックス) をセットアップし、SS:SP と CS:IP をロードするだけで済みました。実アドレス モードではメモリ保護が利用できないため、メモリを保護できませんでした。そのため、16 ビット DOS 実行形式は非常に単純でした。


    Linux
    1. LinuxでSuコマンドを使用する方法

    2. Unixのマニュアルページで二重引用符の代わりに二重引用符を使用するのはなぜですか?

    3. コマンドの使用方法を学ぶためにマニュアルページを使用する方法?

    1. $(pwd)または$ pwdを使用する方が良いですか?

    2. Linux – LinuxでのO_directの使用?

    3. クラウドサーバータグを使用する

    1. LinuxでBusyBoxを使用する方法

    2. Linuxでcronを使用する方法

    3. Nginxを使用してリダイレクトする方法