ローダーが DLL をプロセス アドレス空間にマップする方法を知りたいです。ローダーがその魔法をどのように行うか。例は高く評価されています。
前もって感謝します。
さて、ここでは Windows 側を想定しています。PE ファイルをロードすると、ローダー (NTDLL に含まれる) が次のことを行います。
DLLMain()
の場合、開始アドレスが PE ファイルのエントリ ポイントにあるスレッドを作成します (実際の開始アドレスは Win32 プロセスの kernel32.dll 内にあるため、これも単純化されすぎています)。コードをコンパイルすると、外部関数がどのように参照されるかはリンカに依存します。一部のリンカーはスタブを作成するため、理論的には、NULL に対して関数アドレスをチェックしようとすると、常に NULL ではないと判断されます。これは、リンカーが影響を受けるかどうか、いつ影響を受けるかを認識しておく必要がある癖です。その他は IAT エントリを直接参照します。この場合、参照されていない関数 (遅延ロードされた DLL を考えてください) のアドレスは NULL になる可能性があり、SEH ハンドラーは遅延ロード ヘルパーを呼び出し、関数アドレスを解決 (しようと) してから、実行を再開します。失敗した点。
上記のプロセスには、単純化しすぎた多くの事務処理が含まれています。
あなたが知りたかったことの要点は、プロセスへのマッピングが MMF として発生するということですが、ヒープスペースで動作を人為的に模倣することができます。ただし、CoW に関する要点を覚えていれば、それが DLL の考え方の核心です。実際には、DLL の (ほとんどの) ページの同じコピーが、特定の DLL をロードするプロセス間で共有されます。共有されていないページは、たとえば、移転や同様のことを解決するときに、私たちが書いたページです。この場合、各プロセスには元のページのコピー (現在は変更されています) があります。
そして、DLL 上の EXE パッカーに関する警告です。DLL がロードされるプロセスのヒープ上に、DLL のアンパックされたコンテンツ用のスペースを割り当てるという点で、私が説明したこの CoW メカニズムを正確に無効にします。そのため、実際のファイルの内容は引き続き MMF としてマップされ、共有されますが、展開された内容は、DLL をロードするプロセスごとに、それを共有する代わりに同じ量のメモリを占有します。
どのレベルの詳細を探していますか?基本的なレベルでは、すべてのダイナミックリンカーはほぼ同じように機能します。
本当に興味がある場合は、本Linkers and Loadersを読む必要があります。
これがWindowsにあると仮定すると(DLLはそれを示唆しています)、Microsoftのランタイムダイナミックリンクのドキュメントページを読むことをお勧めします。DLLがアドレス空間にどのようにマップされるかについては詳細に指定されていません。私はあなたがそれを知る必要はないはずだと思います。