なぜセグメンテーションではないのですか?


42

私はオペレーティングシステムとx86アーキテクチャを勉強しています。セグメンテーションとページングについて読んでいる間、現代のOSがメモリ管理をどのように処理するのか自然に興味がありました。私がLinuxや他のほとんどのオペレーティングシステムで見つけたものから、ページングを優先してセグメンテーションを本質的に回避しています。私が見つけたこの理由のいくつかは、シンプルさと移植性でした。

セグメンテーション(x86またはそれ以外)の実用的な用途は何ですか?それを使用する堅牢なオペレーティングシステムが表示されるか、ページングベースのシステムが引き続き使用されます。

今、私はこれがロードされた質問であることを知っていますが、新しく開発されたオペレーティングシステムでセグメンテーションがどのように処理されるか興味があります。ページングを支持することは、「セグメント化された」アプローチを誰も考慮しないほど理にかなっていますか?もしそうなら、なぜですか?


そして、「排除」セグメンテーションと言うとき、Linuxは必要な範囲でのみ使用することを意味します。ユーザーおよびカーネルコード/データセグメント用のセグメントは4つだけです。Intelのドキュメントを読みながら、セグメンテーションはより堅牢なソリューションを念頭に置いて設計されていると感じました。それから、x86がどれほど複雑になるかを何度も言われました。


Linux Torvaldの元々のLinuxの「アナウンスメント」にリンクした後、この興味深い逸話を見つけました。彼はこれについて、いくつかの投稿を後に述べました。

簡単に言えば、移植は不可能だと思います。ほとんどはCで書かれていますが、ほとんどの人は私がCを書いているものとは呼びません。これは、386について教えてくれるプロジェクトでもあったので、386の考えられるすべての機能を使用します。すでに述べたように、 、ページング(まだディスクへではない)とセグメンテーションの両方。本当に386に依存するのはセグメンテーションです(すべてのタスクにはコードとデータ用の64Mbセグメントがあります-4Gbで最大64タスク。64Mb/タスク以上が必要な人は誰でもCookieが強い)。

私自身がx86を試した結果、この質問をするようになったと思います。LinusにはStackOverflowがなかったため、それを実装して試してみました。


どの本を読みましたか?

1
私はたくさんの本を読んでいます。インテルシステムプログラミングマニュアル(第3巻)を読みながらこれを自問し始めましたが、Linuxメモリ管理については、「Linuxカーネルについて」などのオンラインソースで少し読みました。
シカダンス氏11

特に、ローカル記述子テーブルに関するセクションを読んでいて、オペレーティングシステムがこれらをどのように使用しているかに興味がありました。
シカダンス氏11

1
OpenBSDは、x86セグメンテーションとページングを組み合わせて、NXビットシミュレーション(データページの実行を禁止するセキュリティ機能)を取得します。PaXもこれを使用した可能性があります。

私はこの件に関してほとんど何も知らない。検索用の質問を入力したところ、現在使用されているすべてのオペレーティングシステムに関する苦情の回答が表示されました。苦情を見ると、ほとんどの人はいくつかの特定のタスクのためにPCを使用しています。そのため、実行中のすべての周辺機器にアクセスを許可するのではなく、これらのタスクをより速く行うために、より多くのメモリ使用量を割り当てないでください。

回答:


31

たとえば、セグメンテーションを使用すると、動的に割り当てられた各オブジェクト(malloc)を独自のメモリセグメントに配置できます。ハードウェアはセグメント制限を自動的にチェックし、セキュリティバグ(バッファオーバーラン)のクラス全体が排除されます。

また、すべてのセグメントオフセットはゼロから始まるため、コンパイルされたすべてのコードは自動的に位置に依存しません。別のDLLを呼び出すと、(呼び出された関数に応じて)一定のオフセットを持つfar呼び出しに要約されます。これにより、リンカーとローダーが大幅に簡素化されます。

4つの保護リングを使用すると、よりきめの細かいアクセス制御(ページングでは、ユーザーとスーパーバイザーの2つの保護レベルのみ)とより堅牢なOSカーネルを考案できます。たとえば、リング0のみがハードウェアにフルアクセスできます。コアOSカーネルとデバイスドライバーをリング0と1に分けることにより、関連するアクセスチェックのほとんどがHWによって行われる、より堅牢で非常に高速なマイクロカーネルOSを作成できます。(デバイスドライバーは、TSSのI / Oアクセスビットマップを介してハードウェアにアクセスできます。)

ただし.. x86には少し制限があります。「空き」データセグメントレジスタは4つしかありません。それらのリロードはかなり高価であり、同時に8192セグメントにのみアクセスすることが可能です。(アクセス可能なオブジェクトの数を最大化したい場合、GDTはシステム記述子とLDT記述子のみを保持します。)

現在、64ビットモードでは、セグメンテーションは「レガシー」と呼ばれ、ハードウェア制限チェックは限られた状況でのみ行われます。私見、大きな間違い。実際、Intelを非難せず、主に開発者を非難します。開発者の大半は、セグメンテーションが「複雑すぎ」、フラットなアドレス空間を切望していると考えていました。また、セグメンテーションを有効に活用するための想像力に欠けるOSライターを非難します。(AFAIK、OS / 2はセグメンテーション機能をフルに活用した唯一のオペレーティングシステムでした。)


1
これが私がこれを開いたままにしている理由です。この問題については、いくつかの異なる
見解があるはず

1
@zvrba:なんて素晴らしい説明!!! ありがと。今、私は疑問を抱いています。ページングの助けを借りて、セグメントを重複せず、4GB対応にすることで、インテルが大きな賞を獲得できたと思いませんか?私が理解したように、「ページングによるセグメンテーション」は、最大4GBの仮想メモリアドレス空間のみをアドレス指定できることを意味します。そしてそれは「ピーナッツ」です!!! それぞれ4GBのコード、スタック、データセグメントを持ち、必要に応じてオーバーラップまたはオーバーラップしないことを想像してください!そしてそれは、当時のように完全な64ビットアーキテクチャを要求することなく、当時大きな成功を収めていたでしょう。
ファンテ

1
セグメンテーションが優れている理由の素晴らしい説明。道端に落ちたことは恐ろしいことです。詳細を知りたい人のための詳細詳しく説明します。
GDP2

1
OS / 2が大好きだったのも不思議ではありません!無知とマーケティングのおかげで、本当に価値のある技術が何と悲しい損失を被ったか。
イルミナート

セグメンテーションが良い考えだと思う人は誰でも、セグメンテーションがどれほどひどいものかを覚えるのに十分な年齢であってはなりません。それはひどいです。事実上、これまでに作成されたすべてのCコードは、フラットなアドレス空間を想定しています。カーネルがユーザーに表示させない限り、ポインターを見て、アドレスを見ることができ、セグメントベースを掘り下げる必要がなく、それが可能であると仮定すると、x86保護モードセグメンテーションではないので便利です。どういうわけか、非常に高価なシステムコールを使用している可能性が高いです。セグメント全体をスワップアウトしない限り、セグメントをスワップすることはできません。ページングは​​はるかに優れています。
doug65536

25

簡単な答えは、セグメンテーションはハックであり、メモリをアドレス指定する能力が制限されたプロセッサをこれらの制限を超えるために使用することです。

8086の場合、チップには20本のアドレス行があり、1Mbのメモリに物理的にアクセスできることを意味します。ただし、内部アーキテクチャは、おそらく8080との整合性を維持するために、16ビットアドレス指定に基づいていました。したがって、命令セットには、1Mbのメモリ全体のアドレス指定を可能にする16ビットインデックスと組み合わせられるセグメントレジスタが含まれていました。80286は、このモデルを真のMMUで拡張し、セグメントベースの保護とより多くのメモリ(iirc、16Mb)のアドレス指定をサポートしました。

PDP-11の場合、後のプロセッサモデルでは、命令およびデータスペースへのセグメンテーションが提供され、これも16ビットアドレススペースの制限をサポートします。

セグメンテーションの問題は単純です。プログラムは、アーキテクチャの制限を明示的に回避する必要があります。8086の場合、これは、アクセスできるメモリの最大連続ブロックが64kであることを意味していました。それ以上アクセスする必要がある場合は、セグメントレジスタを変更する必要があります。つまり、Cプログラマーにとっては、Cコンパイラーにどの種類のポインターを生成すべきかを伝える必要がありました。

32ビットの内部アーキテクチャと24ビットの物理アドレス空間を備えたMC68kのプログラミングは、はるかに簡単でした。


5
OK、それはすべて理にかなっています。ただし、Intelのドキュメントを読むと、プログラムバグに対するハードウェアレベルの保護を強化するためにセグメントを実際に使用できると考える傾向があります。特にシステムプログラミングガイドのセクション3.2.3-マルチセグメントモデルには利点がありますか?Linuxが保護されたフラットモデルを使用していると言うのは正しいでしょうか?(セクション3.2.2)
Mr. Shickadance

3
Intelのメモリアーキテクチャの詳細に注意を向けてからかなり時間が経ちましたが、セグメント化されたアーキテクチャがハードウェア保護を強化するとは思いません。MMUが提供できる唯一の本当の保護は、コードとデータを分離して、バッファーオーバーラン攻撃を防ぐことです。そして、それページレベルの属性を介して、セグメントなしで制御可能であると信じています。理論的には、オブジェクトごとに個別のセグメントを作成することでオブジェクトへのアクセスを制限できますが、それは合理的ではないと思います。

1
おかげで、セグメント化されたメモリで画像処理を行うことで抑圧されたすべての思い出を取り戻しました-これは、より多くの治療を意味するでしょう!
マーティンベケット

10
セグメンテーションを完全に誤解しています。8086では、ハックだったかもしれません。80286は、保護に不可欠な保護モードを導入しました。80386ではさらに拡張され、セグメントは64kBより大きくなる可能性がありますが、それでもハードウェアチェックの利点があります。(BTW、80286にはMMUがありませんでした。)
zvrba

2
386が導入された1985年に、4 GiBのアドレス空間は巨大であると考えられていました。当時、20 MiBのハードディスクはかなり大きかったので、システムがフロッピーディスクドライブのみを搭載することも珍しくありませんでした。3.5 "FDDは1983年に導入され、なんと360 KBのフォーマットされた容量を誇っています。(1986年に1.44 MB 3.5" FDDが利用可能になりました。) 64ビット:物理的にアプローチ可能ですが、実際には無限大になるほど大きい。
CVn

15

80x86には、「なし」、セグメンテーションのみ、ページングのみ、セグメンテーションとページングの両方の4つのオプションがあります。

「なし」(セグメンテーションまたはページングなし)の場合、プロセスをそれ自体から保護する簡単な方法、プロセスを相互に保護する簡単な方法、物理アドレス空間の断片化などを処理する方法、位置を回避する方法がなくなります。これらの問題にもかかわらず、(理論上)状況によっては有用である場合があります(たとえば、1つのアプリケーションのみを実行する組み込みデバイス、またはJITを使用してとにかくすべてを仮想化するもの)。

セグメンテーションのみ。「プロセスをそれ自体から保護する」問題をほぼ解決しますが、プロセスが8192セグメント(プロセスごとに1つのLDTを想定)を使用する場合に使用できるようにするには、多くの回避策が必要です。「プロセスを相互に保護する」問題をほぼ解決します。ただし、同じ特権レベルで実行されているソフトウェアの異なる部分は、互いのセグメントをロード/使用することができます(それを回避する方法があります-コントロール転送中のGDTエントリの変更やLDTの使用)。また、「位置独立コード」の問題もほとんど解決します(「セグメント依存コード」の問題を引き起こす可能性がありますが、それほど重要ではありません)。「物理アドレス空間の断片化」問題に対しては何もしません。

ページングのみ。「それ自体からプロセスを保護する」問題をあまり解決しません(しかし、正直に言って、これは本当に安全でない言語で書かれたコードをデバッグ/テストするための問題であり、とにかくvalgrindのようなはるかに強力なツールがあります)。「相互からのプロセスの保護」問題を完全に解決し、「位置独立コード」問題を完全に解決し、「物理アドレス空間の断片化」問題を完全に解決します。追加のボーナスとして、ページングなしでは実用的とは言えない非常に強力な手法がいくつか用意されています。「コピーオンライト」、メモリマップファイル、効率的なスワップ領域処理などを含む。

セグメンテーションとページングの両方を使用すると、両方の利点が得られると思います。理論的には、セグメンテーションから得られる唯一の利点(ページングによって改善されない)が、誰も気にしない「プロセスをそれ自体から保護する」問題の解決策である場合を除き、可能です。実際には、両方の複雑さと両方のオーバーヘッドが得られますが、ほとんどメリットはありません。

これが、80x86向けに設計されたほとんどすべてのOSがメモリ管理にセグメンテーションを使用しない理由です(CPUごとおよびタスクごとのストレージなどに使用しますが、これらはより便利な汎用レジスタの消費を避けるために主に便利です)もの)。

もちろん、CPUメーカーは愚かではありません-誰も使用していないと知っているものを最適化するために時間とお金を費やすことはありません(ほとんどの人が代わりに使用するものを最適化します)。このため、CPU製造業者はセグメンテーションを最適化しないため、セグメンテーションが本来よりも遅くなり、OS開発者はそれをさらに避けたいと思うようになります。ほとんどの場合、下位互換性のためにのみセグメンテーションを維持しました(これは重要です)。

最終的に、AMDはロングモードを設計しました。心配する古い/既存の64ビットコードはなかったため、(64ビットコードの場合)AMDはできるだけ多くのセグメンテーションを取り除きました。これにより、OS開発者は、セグメンテーションを回避し続けるもう1つの理由(セグメンテーション用に設計されたコードを64ビットに移植する簡単な方法がない)を得ることができました。


13

この質問が投稿されて以来、セグメント化されたメモリアーキテクチャの起源と、それらが提供できる真のパワーについて誰も言及していないことに、私はかなりst然としています。

セグメント化されたページ化仮想メモリシステムの設計と使用を取り巻くすべての機能(対称型マルチプロセッシングおよび階層ファイルシステムとともに)を発明したか、有用な形式に改良した元のシステムはMulticsでした(Multiciansのサイトも参照)。セグメント化されたメモリにより、Multics はすべてが(仮想)メモリ内にあるというビューをユーザーに提供し、すべての共有の究極のレベルを可能にします。直接形式(つまり、メモリで直接アドレス指定可能)。ファイルシステムは、メモリ内のすべてのセグメントへの単なるマップになります。体系的な方法(Multicsなど)で適切に使用すると、セグメント化されたメモリにより、ユーザーはセカンダリストレージの管理、データの共有、プロセス間通信などの多くの負担から解放されます。他の答えは、セグメント化されたメモリの使用がより困難であるといういくつかの手強い主張をしましたが、これは単に真実ではなく、Multicsは数十年前に大きな成功を収めたことを証明しました。

Intelは80286のセグメント化されたメモリの短縮版を作成しました。80286は非常に強力ですが、その制限により、本当に有用なものには使用できません。80386はこれらの制限を改善しましたが、当時の市場の力は、これらの改善を真に活用できるシステムの成功をほとんど妨げました。過去の教訓を無視することを学ぶ人があまりにも多くなったように思えるので、長年にわたって。

Intelはまた、iAPX 432と呼ばれるより高性能なスーパーマイクロを早期に構築しようとしましたが、これは当時他のどの製品よりもはるかに優れていました。しかし、元の実装は遅すぎたため、それを修正する試みはそれ以上行われませんでした。

Multicsがセグメンテーションとページングをどのように使用したかの詳細な議論は、Paul Greenの論文Multics Virtual Memory-Tutorial and Reflectionsにあります。


1
素晴らしい情報と素晴らしい議論。リンクをありがとう、彼らは貴重です!!!
ファンテ

1
Multicsへのリンクと非常に有益な答えをありがとう!明らかに、セグメンテーションは、私たちが今していることよりも多くの点で優れていました。
GDP2

1
あなたの答えは、大まかな真の宝石です。私たちが失ったこれらの洞察を共有してくれてありがとう。ハードウェアの改良を促す適切なOSの開発を通じて、セグメンテーションに戻ることを期待しています。本当に非常に多くの問題をこのアプローチで改善できました!はるかに高いパフォーマンスレベルで、セグメンテーションを伴うベアメタルで真のOOP言語を取得できるようにさえ聞こえます。
イルミナート

6

セグメンテーションは、16ビットプロセッサで最大1MBのメモリをアドレス指定できるようにするためのハッキング/回避策でした。通常は64Kのメモリにしかアクセスできませんでした。

32ビットプロセッサが登場すると、フラットメモリモデルで最大4GBのメモリをアドレス指定でき、セグメント化の必要がなくなりました-セグメントレジスタは、保護モードでのGDT /ページングのセレクタとして再利用されました(ただし、保護モードが16ビットである)。

また、フラットメモリモードはコンパイラにとってはるかに便利です。16ビットのセグメント化されたプログラムをCで作成できますが、少し面倒です。フラットメモリモデルにより、すべてが簡単になります。


代わりにページングを使用できる場合に、セグメンテーションによって提供される「保護」について多くのことを言っていますか?
シカダンス氏11

1
@氏。Shickadance Segmentationは、いかなる種類のメモリ保護提供しません-メモリ保護には、GDTまたはページングのいずれかを使用してメモリを保護できる保護モードが必要です。
ジャスティン

5

一部のアーキテクチャ(ARMなど)は、メモリセグメントをまったくサポートしていません。Linuxがセグメントにソース依存であった場合、それらのアーキテクチャに簡単に移植することはできませんでした。

全体像を見ると、メモリセグメントの障害は、Cとポインター演算の継続的な人気に関係しています。C開発は、フラットメモリを備えたアーキテクチャでより実用的です。フラットメモリが必要な場合は、メモリページングを選択します。

80年代が始まった頃、Intelは組織として、Adaや他の高レベルプログラミング言語の将来の人気を予測していました。これは基本的に、ひどいAPX432や286のメモリセグメンテーションなど、より壮大な障害の一部が発生した場所です。386では、フラットメモリプログラマに降伏しました。ページングとTLBが追加され、セグメントは4GBにサイズ変更可能になりました。そして、AMDは基本的にx86_64でセグメントを削除しました。ベースregをdont-care / implied-0にしました(TLSの場合はfsを除くと思いますか?)

そうは言っても、メモリセグメントの利点は明らかです。TLBを再作成することなくアドレス空間を切り替えることができます。いつか誰かがセグメンテーションをサポートするパフォーマンス競争力のあるCPUを作り、セグメンテーション指向のOSをプログラムすることができ、プログラマはAda / Pascal / D / Rust / another-langage-that-doesn't-require-flatを作ることができます-それのためのメモリプログラム。


1

セグメンテーションは、アプリケーション開発者にとって大きな負担です。これが、セグメンテーションを廃止するための大きな推進力の源です。

興味深いことに、Intelがこれらの古いモードのすべてのレガシーサポートを削除した場合、i86がどれだけ改善されるのかとよく疑問に思います。ここでは、電力が低いほど、動作が高速になる可能性があります。

Intelが16ビットセグメントで牛乳を苦しめ、開発者の反乱を引き起こしたと主張することができると思います。しかし、最新のアプリを見ると、特に64kのアドレス空間は何もありません。結局、競争はi86のアドレス空間の問題に対して効果的にマーケティングを行うことができたので、彼らは何かをしなければなりませんでした。


1

セグメンテーションにより、ページの翻訳とスワッピングが遅くなります

これらの理由により、セグメンテーションはx86-64で大幅に削除されました。

それらの主な違いは次のとおりです。

  • ページングは​​メモリを固定サイズのチャンクに分割します
  • セグメンテーションにより、各チャンクに異なる幅が許可されます

プロセスのメモリサイズを増やすと、セグメント幅を構成できる方が賢く見えるかもしれませんが、断片化は避けられません。たとえば、

|   | process 1 |       | process 2 |                        |
     -----------         -----------
0                                                            max

プロセス1が大きくなると最終的には次のようになります。

|   | process 1        || process 2 |                        |
     ------------------  -------------
0                                                            max

分割が避けられなくなるまで:

|   | process 1 part 1 || process 2 |   | process 1 part 2 | |
     ------------------  -----------     ------------------
0                                                            max

この時点で:

  • ページを変換する唯一の方法は、プロセス1のすべてのページでバイナリ検索を行うことです。これは、許容できないlog(n)
  • そのセグメントが巨大になる可能性があるため、プロセス1パート1からのスワップは巨大になる可能性があります

ただし、固定サイズのページの場合:

  • すべての32ビット変換は2つのメモリ読み取りのみを行います:ディレクトリおよびページテーブルウォーク
  • すべてのスワップは許容可能な4KiBです

固定サイズのメモリチャンクは単純に管理しやすく、現在のOS設計を支配しています。

参照:https : //stackoverflow.com/questions/18431261/how-does-x86-paging-work

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.