2016-09-25 13 views
27

this文書を参照してください。テキストセグメントは 0x400000から始まります。なぜこの特定の住所が選ばれたのですか?そこには の理由がありますか?同じアドレスがLinuxGNU ldに選択されます。x86_64 ABIのアドレス0x400000がテキストセグメントの先頭に選択されているのはなぜですか?

$ ld -verbose | grep -i text-segment 
    PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; 

このアドレスは32ビットx86実行可能で大きなあるので、それは驚きだ:

$ ld -verbose | grep -i text-segment 
    PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS; 

私は0x080xxxxxアドレスが選ばれた理由を説明しthis questionを読みますi386の場合は ですが、x86_64の変更については説明していません。それについては、 の説明は見つけるのが難しいです。誰かが手掛かりを持っていますか?

+0

https://www.uclibc.org/docs/psABI-x86_64.pdfは最新版(0.99.7)、[OSDev Wikiによる](http://wiki.osdev.org/System_V_ABI#ドキュメント)。 –

+0

0x400000は4MiBなので、これは膨大なページのサポートと関係があります。セクション3.3.3では64KiBまでのページサイズしか許されません。 –

+0

@ivan_pozdeev:https://github.com/hjl-tools/x86-psABI/wiki/X86-psABIには、LaTeXソースのgit HEADリビジョンから構築されたPDFへのリンクがあります。 x86-64のページテーブルは2MBのhugeページ(さらには1GiB)を使用することができ、Linuxは透過的に/機会主義的に匿名メモリを使用しますが、ファイルバックアップのマッピングは行いません。私は、4MBは0から離れているので、インデックス付きNULLポインタderefは通常、有効なページにインデックスを作成しないと思います。あなたは答えて同じことを言っているのが分かります。 –

答えて

28

ボトムライン:amd64が大きなアドレスを使用しているといういくつかの技術的な制限は、効率のためにアドレス空間の下位アドレスを2GiBとすることを推奨しています。したがってスタックはこの範囲外に再配置されています。


  • i386 ABIにおいてスタックはちょうど下0x8048000下方から成長し、コードの前に配置されています。 "スタックに128 MBを少し超え、、テキストとデータに約2 GBを提供します"(p。3-22)。
  • 動的セグメントは
  • 0x80000000(は2GiB)で開始し、カーネルは、specが少なくとも0xC0000000た(p。3-21)から始まる、1GiBまでであることを可能にする上部に「予約領域」を占めます( which is what it typically does)。
  • メインプログラムは、位置に依存しない必要はありません。
  • 実装では、NULLポインタアクセス(p。3-21)をキャッチする必要はありませんが、128MiB(つまり288KiB)のスタック領域の一部がその目的のために予約されることを期待するのが妥当です。

amd64は(whose ABIi386一方(P 9)の改正として製剤化される)非常に大きい(48ビット)のアドレス空間を有しているが、ほとんどの命令は、直接アドレスを含む32ビット即値オペランドを(受け入れますジャンプ命令のオフセット)、より大きな値を扱うためには、より多くの作業と効率の悪いコードが必要です(特に命令の相互依存性を考慮する場合)。これらの制限を回避するための対策は、著者が、「コンパイラがより良いコードを生成できるようにする」ために使用することを推奨するいくつかの「コードモデル」をで紹介することによって要約されています。た(p。33)は、具体的に

  • 、それらの第一、 "小さなコード・モデル" は、0から2 -2 -1または0x00000000からの範囲で」アドレスを使用することを提案します0x7effffff "であり、非常に効率的な相対参照と配列の繰り返しが可能です。これは多くのプログラムにとって十分なものである1.98GiBです。
  • "中程度のコードモデル"は、上記の境界にある "高速"部分とアクセスに特別な命令を必要とする "遅い"部分に分割するに分割したものです。コードは境界線の下に残ります。
  • のコードモデルのように、 "large"モデルだけがサイズについての仮定をしておらず、movabs命令を使用するにはコンパイラ"が必要です。現在の命令ポインタからオフセットされた のアドレスへの分岐が不明な場合に必要です。これらは、境界内にあることがわかっているオフセットを持つ相対参照には適用されないため、コードベースを複数の共有ライブラリに分割することを提案しています(「小さな位置独立コードモデル」で説明)。

そのアドレスが常に別の基準から間接的またはlea/movで参照即値オペランド、ことはありませんので、このようにスタックが共有ライブラリ空間(0x80000000000128GiB)下に移動し、このようにのみ相対オフセットの制限が適用されます。


上記は、ローディングアドレスが下位アドレスに移動された理由を説明しています。今、正確に0x4000004MiB)に移動したのはなぜですか?ここで、私はABIの仕様に何を読んでまとめた、私はそれが「ちょうどいい」と感じたことを推測することができますので、空来た:

  • それは大きなを考慮して、オフセットを任意の可能性が間違った構造をキャッチするのに十分な大きさですamd64が動作するデータユニットであり、アドレス空間の最初の2GiBの多くを無駄にしない程度に小さい。
  • これまでの最大の実際のページサイズと同じで、他のすべての仮想メモリユニットのサイズの倍数です。

時間が経つにつれて、実際のX32のLinuxesは、このレイアウトmoremoreから逸脱していることに注意してください。しかし、ABI仕様については、amd64が公式に基づいているので、ここではABI仕様について言及しています(引用の段落を参照してください)。

関連する問題