0x00400000がEXEのデフォルトのベースアドレスである理由

DLLのデフォルトのベースアドレスは0x10000000ですが、実行可能ファイルの場合は0x00400000です。 なぜEXEに特別な意味があるのですか? 4 メガバイトの特別なところは何ですか?



これは、x86アーキテクチャの単一ページテーブルによって表示されるアドレス空間のサイズに関連しており、この設計は1987年に選択されました。



EXEのベースアドレスの唯一の技術要件は、 64 KBの多重度です 。 ただし、一部のベースアドレスオプションは他のオプションよりも優れています。



ベースアドレスを選択する目的は、モジュールが移動する可能性を最小限にすることです。 これは、1)既にアドレス空間にある他のオブジェクトとの衝突を防ぐ必要があることを意味します(これにより、移動が発生します)。 2)同様に、後でアドレス空間に表示される可能性のあるオブジェクト(それらの移動を強制する)。 実行可能ファイルの場合、後で表示される可能性のあるオブジェクトとの競合を避けることは、DLLで満たされる可能性のあるアドレス空間の領域を残すことを意味します。 オペレーティングシステム自体がDLLファイルを上位アドレスに配置し、非システムDLLのデフォルトのベースアドレスは0x10000000であるため、EXEのベースアドレスは0x10000000よりも若い必要があり、若いほど競合を開始する前により多くのスペースが残りますライブラリ。 しかし、あなたはどれだけ低くしなければなりませんか?



パラグラフ1は、すでにメモリにあるオブジェクトも避ける必要があることを意味します。 Windows NTでは、下位アドレスに多くはありませんでした。 唯一存在したのはPAGE_NOACCESSページで、これはヌルポインターへのアクセス試行をキャッチするためにヌルアドレスを占有していました。 したがって、Windows NTでは、実行可能ファイルをベースアドレス0x00010000に配置できますが、多くのアプリケーションはそれを実行しました。



しかし、Windows 95では、最下位アドレスで、はるかに多くがロードされました。 Windows 95 Virtual Machine Managerは、CPUエラーを回避するために、物理メモリの最初の64 KBを仮想メモリの最初の64 KBに常にマップしました。 (Windows 95 は多くのCPU バグファームウェアバグ を回避する必要 ありました )。 さらに、仮想アドレス空間の最初の1メガバイト全体が、アクティブな仮想マシンの論理アドレス空間にマップされました。 (ペダントの場合: 実際には1メガバイト強 )。 この表示方法は、仮想8086 x86プロセッサモードの要件でした。



Windows 95は、その前身であるWindows 3.1と同様に、Windowsを特別な仮想マシン(System VMと呼ばれる)で実行しましたが、互換性のために、16ビットコードを通じてさまざまなものを渡しました 。 したがって、CPUがWindowsアプリケーション(MS-DOSアプリケーションではなく)を処理した場合でも、仮想マシンのアドレススペースのマッピングは保存されたため、互換モードを開始する必要があるたびに再実行する必要がありません(同時に、 バッファーアドレスを変換するためのリソース集約的な手順 ) MS-DOS



したがって、アドレス空間の最初のメガバイトはシーンを離れます。 他の3メガバイトはどうですか?



ここで、記事の冒頭の小さなヒントに戻ります。



コンテキストをすばやく切り替えるために、Windows 3.1 Virtual Machine Managerは各仮想マシンのコンテキストを4 MBに切り上げました。 彼は、ページテーブルの1つの32ビット値を更新することでコンテキストを切り替えることができるように行動しました。 (ペダントの場合: 属性ページも処理する必要がありますが、これは数十ビット程度です)。 丸めにより、3メガバイトのアドレス空間が失われますが、4ギガバイトのアドレス空間が利用可能であるため、0.1%未満の損失は、大幅なパフォーマンス向上のための小さな犠牲のように見えます。 (さらに、その時点では、単一のアプリケーションがこの制限に近づいていませんでした。一般に、コンピューターには2 MBの物理メモリしかありませんでした)。



メモリの表示方法がWindows 95に移行され、32ビットWindowsアプリケーションの個別のアドレススペースを操作するための修正が加えられました 。 この結果、Windows 95で実行可能ファイルをダウンロードできる最下位アドレスは4 MB、つまり0x00400000でした。



オタクのためのトリビア。 Win32アプリケーションがMS-DOS互換モード使用されるメモリ領域にアクセスするの防ぐため 、単純なデータセレクターは実際には4 MBの境界で停止する拡張可能なダウンセレクターでした。 (同様に、16ビットWindowsアプリケーションのNULLポインターは、NULLセレクターが無効だったため、アクセス違反になりました)。



リンカは、実行可能ファイルのデフォルトのベースアドレスとして0x0400000を選択しているため、EXEはWindows NTとWindows 95の両方で移動せずにロードできます。Windows95での最適化は誰も気にしません。別のデフォルトベースアドレスを選択できます。 しかし、特にASLRがこの調和に疑問を抱いているため、図の調和の美的喜びを除いて、これを行うための特別なインセンティブはありません。 さらに、ベースアドレスを変更すると、人々は「なぜ一部の実行可能ファイルのベースアドレスは0x04000000で、他の実行可能ファイルは0x00010000なのですか?」と尋ね始めるでしょう。



TL; DR:コンテキストをすばやく切り替えます。



All Articles