最近、Windows の PE 形式を調べていて、ほとんどの例で、 のImageBase
オフセット値を のoptional header
ように不当に高い値に設定する傾向があることに気付きました0x400000
。
オフセットで画像をマッピングしないことが好ましくない理由は何0x0
ですか?
最近、Windows の PE 形式を調べていて、ほとんどの例で、 のImageBase
オフセット値を のoptional header
ように不当に高い値に設定する傾向があることに気付きました0x400000
。
オフセットで画像をマッピングしないことが好ましくない理由は何0x0
ですか?
まず、これは Windows や PE ファイル形式のデフォルトではありません。リンカーの /BASE オプションを使用して EXE をリンクする場合のデフォルトです。DLL のデフォルトは 0x10000000 です。
/BASE:0 を選択するのは悪い選択です。そのベース アドレスでプログラムを実行することはできません。アドレス空間の最初の 64 KB は予約されており、マップできません。主に null ポインター逆参照のバグをキャッチします。また、16 ビットで開始され、32 ビットに再コンパイルされたプログラムのポインター バグを検出するために、64KB に拡張されました。
0x10000 ではなく 0x40000 がデフォルトである理由も歴史的な事故であり、少なくとも Windows 95 にまでさかのぼります。これは、「16 ビット/MS-DOS 互換アリーナ」用にアドレス空間の最初の 4 メガバイトを予約しました。私はそれについてあまり覚えていません.Windows 9xには、NTとは非常に異なる16ビットVM実装がありました. 詳細については、この古いKB 記事を参照してください。64 ビット OS は 0x010000 と 0x400000 の間のスペースにヒープ メモリを簡単に割り当てます。
EXE の /BASE オプションを変更しても意味がありません。ただし、DLL 用に変更することには多くのポイントがあります。オーバーラップせず、再配置する必要がなく、ページング ファイルでスペースを占有せず、プロセス間で共有できる場合は、はるかに効果的です。そのための SDK ツールもあるので、ビルド後に変更できます rebase.exe
アドレス 0 にマップすると、コードはアドレス 0 から実行されることを期待することになります。
OS の場合、アドレス 0 はNULL
無効なアドレスです。
(「根本的に」ではありませんが、現代のOSではそうです。)
また、一般に、メモリの下位 16 MiB (仮想メモリであっても) には何も入れたくないという理由が多数あります。
しかし、代替手段は何ですか?どこかにマッピングする必要があるため、彼らが選択したのは0x400000
...おそらくその特定のアドレスに特別な理由はありません。それはおそらくちょうど便利でした。
Microsoft は、PE ファイルがメモリ マップされるリンカーによって指定される既定の開始アドレスとして、そのアドレスを選択しました。リンカーはこのアドレスを想定し、その想定で実行可能ファイルを最適化できます。ファイルがそのアドレスにメモリ マップされている場合、内部オフセットを変更する必要なくコードを実行できます。
何らかの理由でファイルをその場所にロードできない場合 (別の exe/dll が既にロードされている場合)、実行可能ファイルを実行する前に再配置を行う必要があり、ロード時間が長くなります。
通常、下位メモリ アドレスには低レベルのシステム ルーチンが含まれていると想定され、通常はそのままにしておきます。ImageBase アドレスの唯一の実際の要件は、0x10000 の倍数であることです。
推奨読書: