web-dev-qa-db-ja.com

Linuxはセグメンテーションを使用せず、ページングのみを使用しますか?

Linuxプログラミングインターフェイスは、プロセスの仮想アドレス空間のレイアウトを示します。図の各領域はセグメントですか?

enter image description here

からUnderstanding The Linux Kernel

MMU=のセグメンテーションユニットがセグメントとセグメント内のオフセットを仮想メモリアドレスにマップし、ページングユニットが仮想メモリアドレスを物理メモリアドレスにマップすることを意味します。 ?

メモリ管理ユニット(MMU)は、セグメンテーションユニットと呼ばれるハードウェア回路によって論理アドレスを線形アドレスに変換します。次に、ページングユニットと呼ばれる2番目のハードウェア回路が、リニアアドレスを物理アドレスに変換します(図2-1を参照)。

enter image description here

では、なぜLinuxはセグメンテーションを使用せず、ページングのみを使用すると言っているのですか?

80x86マイクロプロセッサーにはセグメンテーションが含まれており、プログラマーがアプリケーションをサブルーチンやグローバルおよびローカルデータ領域などの論理的に関連するエンティティに分割できるようになっています。ただし、Linuxは非常に限られた方法でセグメンテーションを使用します。実際、セグメンテーションとページングは​​どちらも物理アドレス空間を分離するために使用できるため、多少冗長ですプロセスの:セグメンテーションは各プロセスに異なる線形アドレススペースを割り当てることができますが、ページングは​​同じ線形アドレススペースを異なる物理アドレススペースにマップできます。 Linuxは、次の理由により、セグメンテーションよりもページングを優先します。

•すべてのプロセスが同じセグメントレジスタ値を使用する場合、つまり、同じリニアアドレスセットを共有する場合、メモリ管理はより簡単になります。

•Linuxの設計目標の1つは、幅広いアーキテクチャへの移植性です。特にRISCアーキテクチャでは、セグメンテーションのサポートが制限されています。

Linuxの2.6バージョンは、80x86アーキテクチャで必要な場合にのみセグメンテーションを使用します。

27
Tim

x86-64アーキテクチャは、ロングモード(64ビットモード)でセグメンテーションを使用しません。

4つのセグメントレジスタ:CS、SS、DS、ESは強制的に0に制限され、制限は2 ^ 64に制限されます

https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments

OSが使用可能な「リニアアドレス」の範囲を制限することはできなくなりました。したがって、メモリ保護にセグメンテーションを使用することはできません。ページングに完全に依存する必要があります。

レガシー32ビットモードで実行する場合にのみ適用されるx86 CPUの詳細について心配する必要はありません。 32ビットモードのLinuxはあまり使用されていません。それは「数年間無害な状態にある」とさえ考えられるかもしれません。 Fedoraでの32ビットx86のサポート [LWN.net、2017]を参照してください。

(32ビットLinuxもセグメンテーションを使用しないことがあります。しかし、私を信頼する必要はありません。無視してください:-)。

21
sourcejedi

図の各領域はセグメントですか?

番号。

セグメンテーションシステム(x86の32ビットプロテクトモード)は、個別のコード、データ、スタックセグメントをサポートするように設計されていますが、実際にはすべてのセグメントが同じメモリ領域に設定されています。つまり、0から始まり、メモリの最後で終わります。(*)。これにより、論理アドレスと線形アドレスが等しくなります。

これは「フラット」メモリモデルと呼ばれ、個別のセグメントがあり、その中にポインタがあるモデルよりもやや単純です。特に、セグメント化されたモデルでは、オフセットポインターに加えてセグメントセレクターを含める必要があるため、より長いポインターが必要です。 (16ビットセグメントセレクタ+ 32ビットオフセットで合計48ビットポインタ。32ビットフラットポインタのみ。)

64ビットのロングモードは、フラットメモリモデル以外のセグメンテーションも実際にはサポートしていません。

286で16ビット保護モードでプログラムする場合、アドレス空間は24ビットですが、ポインターは16ビットしかないため、セグメントがさらに必要になります。

(* 32ビットLinuxがカーネル/ユーザースペースの分離をどのように処理するか思い出せないことに注意してください。セグメンテーションでは、カーネルスペースが含まれないようにユーザースペースセグメントの制限を設定することでそれが可能になります。ページングは​​、ページごとの保護レベル。)

では、なぜLinuxはセグメンテーションを使用せず、ページングのみを使用すると言っているのですか?

X86にはまだセグメントがあり、無効にすることはできません。それらはできるだけ少なく使用されます。 32ビット保護モードでは、セグメントをフラットモデル用に設定する必要があります。64ビットモードでも、セグメントはまだ存在しています。

9
ilkkachu

X86にはセグメントがあるため、それらを使用しないことはできません。ただし、cs(コードセグメント)とds(データセグメント)の両方のベースアドレスがゼロに設定されているため、セグメンテーションは実際には使用されません。例外はスレッドローカルデータで、通常は未使用のセグメントレジスタの1つがスレッドローカルデータを指します。ただし、これは主に、このタスク用の汎用レジスターの1つを予約することを避けるためです。

Linuxがx86でセグメンテーションを使用しないとは言われていません。それは不可能だからです。 Linuxは非常に限られた方法でセグメンテーションを使用していますをすでにハイライトしています。 2番目の部分はLinuxは、80x86アーキテクチャで必要な場合にのみセグメンテーションを使用します

あなたはすでに理由を引用しました、ページングは​​より簡単でよりポータブルです。

8
RalfFriedl

図の各領域はセグメントですか?

これらは、単語「セグメント」のほぼ完全に異なる2つの使用法です

  • x86セグメンテーション/セグメントレジスタ:最新のx86 OSは、32ビットモードですべてのセグメントが同じbase = 0およびlimit = maxであるフラットメモリモデルを使用し、ハードウェアが64で強制するのと同じ-ビットモード、セグメンテーションを一種の痕跡的なものにします。 (FSまたはGSを除き、64ビットモードでもスレッドローカルストレージに使用されます。)
  • リンカー/プログラムローダーセクション/セグメント。 ( ELFファイル形式のセクションとセグメントの違いは何ですか

使用法には共通の起源があります。セグメント化されたメモリモデル(特にページングされた仮想メモリがないモデル)を使用している場合、データとBSSアドレスがDSセグメントベース、SSベースに関連するスタック、CSベースアドレスに関連するコード。

したがって、セグメントベースに関連する16ビットまたは32ビットのオフセットを変更せずに、複数の異なるプログラムを異なる線形アドレスにロードしたり、起動後に移動したりすることもできます。

しかし、ポインタがどのセグメントに関連しているかを知る必要があるため、「遠いポインタ」などが必要になります。 (実際の16ビットx86プログラムは、多くの場合、データとしてコードにアクセスする必要がなかったため、どこかで64kコードセグメントを使用でき、おそらく、DS = SSを使用する別の64kブロックを使用できます。または、すべてのセグメントベースが等しい小さなコードモデル)。


X86セグメンテーションとページングの相互作用

32/64ビットモードでのアドレスマッピングは次のとおりです。

  1. segment:offset(オフセットを保持するレジスタによって暗黙的に示される、または命令のプレフィックスでオーバーライドされるセグメントベース)
  2. 32ビットまたは64ビットの線形仮想アドレス= base + offset。 (Linuxが使用するフラットメモリモデルでは、ポインター/オフセット=線形アドレスも。FSまたはGSに関連するTLSにアクセスする場合を除きます。)
  3. ページテーブル(TLBによってキャッシュされる)は、32(レガシーモード)、36(レガシーPAE)、または52ビット(x86-64)の物理アドレスにリニアにマップします。 ( https://stackoverflow.com/questions/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ) 。

    この手順はオプションです。起動時に制御レジスタのビットを設定して、ページングを有効にする必要があります。ページングがない場合、線形アドレスは物理アドレスです。

セグメンテーションではできないことに注意してください単一のプロセス(またはスレッド)で32または64ビットを超える仮想アドレス空間を使用できます、すべてがマッピングされるフラット(線形)アドレス空間は、オフセット自体と同じビット数しかないためです。 (これは16ビットx86の場合ではありませんでした。セグメンテーションは、主に16ビットのレジスタとオフセットで64kを超えるメモリを使用するのに実際に役立ちました。)


CPUは、GDT(またはLDT)からロードされたセグメント記述子を、セグメントベースを含めてキャッシュします。ポインターを逆参照すると、それがどのレジスタにあるかによって、デフォルトでDSまたはSSがセグメントとして使用されます。レジスター値(ポインター)は、セグメント・ベースからのオフセットとして扱われます。

セグメントベースは通常ゼロなので、CPUはこれを特別な場合に行います。または、別の見方をすると、doにゼロ以外のセグメントベースがある場合、ベースアドレスの追加をバイパスする「特別な」(通常の)ケースでは、適用します。


Linuxがx86セグメントレジスタをセットアップする方法:

CS/DS/ES/SSのベースと制限は、32ビットモードと64ビットモードではすべて0/-1です。すべてのポインタが同じアドレス空間を指すため、これはフラットメモリモデルと呼ばれます。

(AMD CPUアーキテクトは、64ビットモードのフラットメモリモデルをenforcingしてセグメンテーションを打ち消しました。メインストリームOSはそれを使用していなかったためです。 PAEまたはx86-64ページテーブル形式でページングすることにより、はるかに良い方法です。)

  • TLS(スレッドローカルストレージ):FSとGSはnotロングモードのbase = 0で固定されています。 (これらは386の新機能であり、ESを使用するrep- string命令でさえも、どの命令でも暗黙的に使用されていません)。 x86-64 Linuxは、各スレッドのFSベースアドレスをTLSブロックのアドレスに設定します。

    例えばmov eax, [fs: 16]は、32ビット値を16バイトからこのスレッドのTLSブロックにロードします。

  • cSセグメント記述子は、CPUのモード(16/32/64ビット保護モード/ロングモード)を選択します。 Linuxは、すべての64ビットユーザー空間プロセスに単一のGDTエントリーを使用し、すべての32ビットユーザー空間プロセスに別のGDTエントリーを使用します。 (CPUが正しく機能するためには、DS/ESも有効なエントリに設定する必要があり、SSも同様です)。また、特権レベル(カーネル(リング0)とユーザー(リング3))を選択するため、64ビットのユーザー空間に戻った場合でも、カーネルはCSが変更されるように調整する必要があり、代わりにiretまたはsysretを使用します。通常のジャンプまたはret命令。

  • X86-64では、syscallエントリポイントはswapgsを使用して、GSをユーザー空間のGSからカーネルのGSに切り替えます。これは、このスレッドのカーネルスタックを見つけるために使用されます。 (スレッドローカルストレージの特殊なケース)。 syscall命令は、スタックポインターをカーネルスタックを指すように変更しません。カーネルがエントリポイントに到達しても、ユーザースタックを指している1

  • DS/ES/SSも、CPUがプロテクトモード/ロングモードで動作するために有効なセグメント記述子に設定する必要があります。ただし、これらの記述子のベース/制限はロングモードでは無視されます。

基本的にx86セグメンテーションはTLSに使用され、ハードウェアが実行する必要がある必須のx86 osdevのものに使用されます


脚注1:おもしろい歴史:AMD64シリコンがリリースされる数年前のカーネル開発者とAMDアーキテクトの間のメッセージのメーリングリストアーカイブがあり、その結果、syscallの設計が微調整されて使用可能になりました。詳細は this answer のリンクを参照してください。

3
Peter Cordes

Linux x86/32は、すべてのセグメントを同じ線形アドレスと制限に初期化するという意味でセグメンテーションを使用しません。 x86アーキテクチャでは、プログラムにセグメントが必要です。コードはコードセグメントからのみ実行でき、スタックはスタックセグメントにのみ配置でき、データはデータセグメントの1つでのみ操作できます。 Linuxは、すべてのセグメントを同じ方法で設定することでこのメカニズムをバイパスします(ただし、本には何も記載されていません)。したがって、どのセグメントでも同じ論理アドレスが有効です。これは実際にはセグメントをまったく持たないことと同じです。

3