web-dev-qa-db-ja.com

x86_64 ABIでアドレス0x400000がテキストセグメントの開始として選択されるのはなぜですか?

this pのドキュメント。 27テキストセグメントは0x400000から始まると書かれています。この特定の住所が選ばれたのはなぜですか?その理由はありますか? LinuxGNU ldで同じアドレスが選択されています。

$ 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;

この質問 を読みました。これは、i386に0x080xxxxxアドレスが選択された理由について説明していますが、x86_64の変更については説明していません。その問題についての説明を見つけるのは難しいです。誰か手がかりがありますか?

32
user1042840

結論:大きなアドレスを使用する際に_AMD64_が持ついくつかの技術的な制限は、効率のためにアドレス空間の低い_2GiB_をコードとデータに割り当てることを示唆しています。したがって、スタックはこの範囲外に再配置されました。


_i386_ ABI1

  • スタックはコードの前にあり、_0x8048000_のすぐ下から下に向かって成長します。これにより、"スタックに128MB強、テキストとデータに約2GB"(p。3-22)が提供されます。
  • 動的セグメントは_0x80000000_(2GiB)で始まり、
  • カーネルは上部の「予約領域」を占め、仕様では少なくとも_1GiB_(p。3-21)( これが何であるか)から開始して、最大_0xC0000000_まで可能です。通常はそうです )。
  • メインプログラムは、位置に依存しない必要はありません。
  • Nullポインタアクセス(p。3-21)をキャッチするために実装は必要ありませんが、_128MiB_(_288KiB_)より上のスタックスペースの一部がその目的のために予約されると予想するのは合理的です。

_AMD64_( そのABI は_i386_の修正として定式化されます(p。9))は、非常に大きな(48ビット)アドレス空間を持ちますが、ほとんどの命令は受け入れるだけです32ビットの即値オペランド(ジャンプ命令の直接アドレスとオフセットを含む)。より大きな値を処理するには、より多くの作業と効率の低いコード(特に命令の相互依存性を考慮した場合)が必要です。これらの制限を回避するための対策は、「コンパイラがより良いコードを生成できるようにする」ために使用することを推奨するいくつかの「コードモデル」を導入することによって著者によって要約されています。(p 。33)

  • 具体的には、最初の「スモールコードモデル」は、0から2の範囲のアドレス"を使用することを提案しています。31-224-1または_0x00000000_から_0x7effffff_ "まで。これにより、非常に効率的な相対参照と配列の反復が可能になります。これは_1.98GiB_であり、多くのプログラムには十分すぎるほどです。
  • 「中程度のコードモデル」は前のモデルに基づいており、splittingデータを上記の境界の下の「速い」部分と特別な必要がある「遅い」残りの部分に分割しますアクセスするための指示。コードは境界の下にとどまりますが。
  • また、「ラージ」モデルのみがサイズについての仮定を行わないため、テキストセクション内のアドレスを処理する場合でも、中コードモデルの場合と同様にコンパイラ"でmovabs命令を使用する必要があります。 、現在の命令ポインタからのオフセットが不明なアドレスに分岐する場合は、間接分岐が必要です。 "これらの測定値はオフセットのある相対参照には適用されないため、コードベースを複数の共有ライブラリに分割することを提案します。範囲内にあることが知られています(「小さな位置に依存しないコードモデル」で概説されています)。

したがって、スタックは共有ライブラリスペース(_0x80000000000_、_128GiB_)の下に移動されました。これは、そのアドレスが即時オペランドではなく、常に間接的に、または別の参照からlea/movで参照されるため、相対オフセット制限のみであるためです。適用します。


上記は、ロードアドレスがより低いアドレスに移動された理由を説明しています。さて、なぜそれは正確に_0x400000_(_4MiB_)に移動されたのですか?ここで、私は空になったので、ABI仕様で読んだことを要約すると、それが「ちょうどいい」と感じたと推測することしかできません。

  • これは、誤っている可能性のある構造オフセットをキャッチするのに十分な大きさであり、_AMD64_が動作するより大きなデータユニットを可能にしますが、アドレス空間の貴重な開始_2GiB_の多くを無駄にしないほど十分に小さいです。
  • これは、これまでの最大の実用的なページサイズに等しく、考えられる他のすべての仮想メモリユニットサイズの倍数です。

1実際のx32Linuxは、時間の経過とともにこのレイアウトから逸脱していることに注意してください more および more 。ただし、ここではABI仕様について説明しています。これは、_AMD64_仕様が、派生レイアウトではなく正式にABI仕様に基づいているためです(引用については、その段落を参照してください)。

31
ivan_pozdeev