2017-02-03 7 views
0

以下の画像は、書籍Programming from the Ground Upから引用しています。Linuxプログラムのメモリレイアウトスキーマについてのご質問

enter image description here

  • プログラムメモリ領域は0xbfffffff0x8048000の間に制限されるのはなぜ?この選択の根底にある根拠は何ですか?この地域の外には何がありますか?

  • この図は、32ビットプログラムである必要があります。 64ビットプログラムのメモリレイアウトとは何ですか?

  • 画像に「起動時」と表示されるため、実行中にレイアウトが変更されますか?

  • 最後に、Linuxカーネルもこのレイアウトに従っていますか?

答えて

4
  • Linuxの32ビットx86上では、伝統的に、3G/1Gユーザー/カーネル分割がありました。

    • ユーザ空間メモリが常に(すなわち、直接32ビットモードで対処することができる4ギガバイトののうち、下位3ギガバイトである)0x00000000-0xBFFFFFFF範囲にマッピングされます。プロセス全体を切り替えるときに、このスペース全体が再マッピングされます。

    • カーネルメモリは、常に0xC0000000-0xFFFFFFFFの範囲(上位1GB)にマップされます。ユーザー空間の特権レベルではアクセスできませんが、カーネルへのコンテキスト切り替えが発生すると、何も再マップせずにすべてのメモリにアクセスできます。

    私はolder answerを持っています。これについてはもう少し詳しく説明します。

  • x86では、スタックは下向き(高く開始し、下位アドレスに向かって)に成長します。これは、CPUデザイン(これは、/pop/call/retの指示が%espになる)の任意の決定です。 Linuxはその範囲の先頭で起動します。

    対照的に、プログラムデータはデフォルトでローエンドにマップされます。歴史的には、カーネルは0x08000000以下にマッピングされていたため、ユーザー空間で使用できる最小アドレスはそれを上回りました。これはもはや真実ではありませんが、元の0x08040000ロードアドレスを説明しています。

  • 中間のスペースがヒープに使用されます。 「ブレイク」マーカーは、brk()またはsbrk()の呼び出しによって上下に移動します。その下にあるメモリはプログラム使用のためにアクセス可能です。歴史的に、Cランタイムは、プログラムのブレークアップを移動させて、スペース要件を満たすためにmallocを実行します。

  • 現在の64ビットx86 CPUでは、アドレス0x0000000000000000-0x00007FFFFFFFFFFFと0xFFFF800000000000-0xFFFFFFFFFFFFFFFFのみが標準です。 64ビットポインタであるが、使用可能なアドレス空間の「唯一の」48ビット分である。 (これは256TBなので、その限界に達するまでしばらく時間がかかります)。非正規アドレス(0x0000800000000000-0xFFFF7FFFFFFFFFFF)にアクセスしようとすると、ハードウェアによって障害が発生します。 Linuxは下半分のユーザー空間と上位半分のカーネルをマップします。

    スタックはまだ成長しているので、Linuxはまだ範囲の先頭に向かって起動し、固定マッピングは下に向かって開始し、ヒープはそれらの上に成長します。

  • はい。ヒープが大きくなったり小さくなったりするプログラムのブレークに加えて、プログラムはmmap/munmapを使用して、ファイル、共有メモリ、匿名メモリなどのアドレス空間にさまざまなものをマップ/アンマップすることもできます。 、最近のCランタイムは、プログラムブレークに加えて、またはプログラムブレークを操作する代わりに、匿名メモリをチャンクにマップします。

  • カーネル自体は、32ビットx86では上位1Gに、64ビットx86では上位128TBに存在します。そのレイアウトは、ユーザ空間にほとんど重要でない(と見えない)であるが、その他のすべてのカーネルスレッドのスタックと、すべてのユーザー・スレッドのカーネル側、ページテーブル、キャッシュ、DMAバッファ、

その他注意事項などのものが含まれます:

これはすべて仮想アドレスであり、物理アドレスではありません。

ユーザ空間へのアクセス最下位アドレスは0 CプログラムはNULLは(それが実際に有効であるかどうexploitsにつながることができます)不正なアドレスであることを期待し、カーネルがどの今64kのデフォルト/proc/sys/vm/mmap_min_addrを強制する必要はないです。

Linux(最近10年以上)は、VDSOを極端な高いアドレスにマップするため、スタックはそれよりも下に開始されます。かつて、vsyscallのページもそこにありましたが、現在はカーネル空間のページにあります。

ASLRのため、すべてのアドレスがシャッフルされている可能性があります。これは32ビットのアドレス空間ではあまり効果的ではありません(他の制約のために、ページの整列のために下位12ビットをランダム化することはできません)が、64ビットモードではたくさんのビットがあります。

+1

私は最初のスタックレイアウトに触れる別の[古い回答](http://stackoverflow.com/a/12016560/20713)を持っています。 Linuxはスタック上の環境変数とコマンドライン引数を持つすべてのプログラムを起動します。これはCランタイムが 'main()'の前に配置します。 – ephemient

関連する問題