1. ホーム
  2. c++

[解決済み] インポートライブラリの仕組みを教えてください。詳細は?

2023-01-11 21:57:31

質問

私は、これがギークにとって非常に基本的なことに見えるかもしれないことを知っています。しかし、私はそれを明確にしたいのです。

Win32 DLL を使いたいとき、通常は LoadLibrary() や GetProcAdderss() のような API を呼び出すだけです。しかし、最近、DirectX9 で開発しているのですが、DirectX9 に対応するために d3d9.lib , d3dx9.lib などのファイルがあります。

LIBは静的リンク用、DLLは動的リンク用というのは十分聞いたことがあるのですが。

つまり、私の現在の理解は、LIB はメソッドの実装を含み、最終的な EXE ファイルの一部としてリンク時に静的にリンクされるということです。一方、DLL は実行時にダイナミックにロードされ、最終的な EXE ファイルの一部ではありません。

しかし、時々、いくつかのLIBファイル で来ることがあります。 が付いてくることがあるので、その場合は

  • これらの LIB ファイルは何のためにあるのですか?
  • どのように目的を達成するのでしょうか?
  • これらの LIB ファイルの内部を検査することができるツールはありますか。

アップデート 1

wikipediaで調べたところ、このLIBファイルというのは インポートライブラリ . しかし、私はそれが私のメインアプリケーションと動的にロードされるDLLでどのように動作するのか疑問に思っています。

更新 2

RBerteigが言ったように、DLLと一緒に生まれるLIBファイルには、いくつかのスタブコードがあります。そのため、呼び出しの順序はこのようになります。

私のメインアプリケーション --> LIBのスタブ --> 実際のターゲットDLL

では、これらのLIBにはどのような情報が含まれていればよいのでしょうか。私は次のようなものを思いつきました。

  • LIB ファイルには、対応する DLL のフルパスが含まれている必要があります。
  • 各 DLL エクスポートメソッドのエントリポイントの相対アドレス (またはファイルオフセット?) は、スタブ内でエンコードされるべきです。

私はこれに関して正しいでしょうか。もっと何かあるのでしょうか?

ところで、インポートライブラリを検査できるツールはないのでしょうか?これがあればもう迷うことはないのですが。

どのように解決するのですか?

DLL ファイルへのリンクが発生することがある 暗黙のうちに で <ストライク コンパイル リンク時、あるいは 明示的に を実行時に指定します。いずれの方法でも、DLL はプロセスのメモリ空間にロードされ、そのエクスポートされたすべてのエントリ ポイントがアプリケーションで使用できるようになります。

実行時に明示的に使用する場合は LoadLibrary()GetProcAddress() を使用して手動で DLL をロードし、呼び出す必要のある関数へのポインタを取得します。

プログラムがビルドされたときに暗黙的にリンクされた場合、プログラムで使用される各 DLL エクスポート用のスタブがインポートライブラリからプログラムにリンクされ、これらのスタブはプロセスの起動時に EXE と DLL がロードされると更新されます。(そう、ここでは少なからず簡略化しているのです...)

これらのスタブはどこかから来る必要があり、Microsoft のツール チェーンでは、.LIB ファイルの特別な形式である インポートライブラリ . 必要な .LIB は通常 DLL と同時に構築され、DLL からエクスポートされる各関数のスタブが含まれています。

紛らわしいことに、同じライブラリの静的バージョンも .LIB ファイルとして出荷されます。DLL のインポート ライブラリである LIB は、一致する静的な LIB よりも通常は小さい (多くの場合はるかに小さい) ことを除いて、これらを区別する些細な方法はありません。

ちなみに、GCC ツールチェーンを使用する場合、DLL に一致するインポートライブラリは実際には必要ありません。Windows に移植された Gnu リンカーのバージョンは DLL を直接理解し、必要なスタブのほとんどをその場で合成することができます。

アップデート

すべてのナットとボルトが本当はどこにあるのか、何が本当に起こっているのか、どうしても知りたくなったら、MSDN にはいつでも助けになるものがあります。Matt Pietrek の記事 Win32 Portable Executable File Format の徹底的な調査 は、EXE ファイルのフォーマットと、それがどのようにロードされ実行されるのかについての非常に完全な概要です。2002 年頃の MSDN Magazine に掲載されて以来、.NET やその他をカバーするために更新されています。2002.

また、プログラムによって使用される DLL を正確に知る方法を知っておくことも役に立ちます。そのためのツールが Dependency Walker (別名 depends.exe) です。このツールのバージョンは Visual Studio に含まれていますが、最新バージョンは作者から次のサイトで入手可能です。 http://www.dependencywalker.com/ . これは、リンク時に指定されたすべての DLL (早期ロードと遅延ロードの両方) を識別でき、またプログラムを実行して、実行時にロードする追加の DLL を監視することも可能です。

アップデート 2

再読の際に明確になるように、以前の文章の一部を言い換え、美術用語である 暗黙的 明示的なリンク を追加し、MSDN との整合性を図りました。

ライブラリ関数をプログラムで使用できるようにするための 3 つの方法があります。どの方法を選択すればよいのでしょうか?

静的リンクは、プログラム自体の大部分をリンクする方法です。すべてのオブジェクト ファイルがリストされ、リンカーによって EXE ファイルに収集されます。その過程で、リンカーはグローバル シンボルへの参照を修正して、モジュールが互いの関数を呼び出せるようにするなどの細かい作業を行います。ライブラリは静的にリンクされることもあります。ライブラリを構成するオブジェクトファイルは、ライブラリアンによって .LIB ファイルにまとめられ、リンカーは必要なシンボルを含むモジュールを検索します。静的リンクの効果の1つは、ライブラリからプログラムで使用されるモジュールだけがリンクされ、他のモジュールは無視されることです。例えば、従来のCの数学ライブラリには、多くの三角関数が含まれています。しかし、もしあなたがそれに対してリンクして cos() のコードのコピーで終わるわけではありません。 sin() または tan() などの関数も呼び出さなければなりません。豊富な機能を持つ大規模なライブラリでは、このようなモジュールの選択的な取り込みは重要です。組み込みシステムなどの多くのプラットフォームでは、デバイスに実行ファイルを格納するためのスペースに比べて、ライブラリで使用できるコードの総容量が大きくなることがあります。選択的なインクルージョンがなければ、そうしたプラットフォーム向けのプログラム構築の詳細を管理することは難しくなるでしょう。

しかし、コピーを持つことで と同じ ライブラリのコピーを実行することは、通常多くのプロセスを実行するシステムにとって負担となります。適切な種類の仮想メモリ システムでは、同一のコンテンツを持つメモリ ページはシステム内に 1 回だけ存在すればよく、多くのプロセスで使用することが可能です。このため、コードを含むページが、できるだけ多くの他の実行中のプロセスのあるページと同一である可能性が高くなるという利点が生まれます。しかし、プログラムがランタイムライブラリに静的にリンクしている場合、各プロセスのメモリマップの異なる場所にそれぞれ異なる関数の組み合わせが配置されており、それ自体が複数のプロセスで実行されるプログラムでなければ、共有できるコードページは多くありません。そのため、DLL のアイデアはもう 1 つの大きな利点を獲得しました。

ライブラリの DLL はそのすべての機能を含んでおり、どのクライアントプログラムでもすぐに使用できます。多くのプログラムがその DLL をロードする場合、すべてのプログラムがそのコードページを共有することができます。誰もが得をするのです。(まあ、DLL を新しいバージョンに更新するまではそうですが、それはこの話には関係ないでしょう。その辺の話は DLL 地獄でググってください)。

新しいプロジェクトを計画するときに行う最初の大きな選択は、動的リンクと静的リンクのどちらを選択するかということです。静的リンクでは、インストールするファイルが少なくなり、使用する DLL を第三者が更新する可能性がなくなります。しかし、プログラムの規模が大きくなり、Windowsのエコシステムの良い一員とは言えなくなります。ダイナミック リンクでは、インストールするファイルが増え、使用する DLL を第三者が更新する問題が発生する可能性がありますが、一般にシステム上の他のプロセスに対してより友好的です。

DLL の大きな利点は、メイン プログラムを再コンパイルまたは再リンクさえせずにロードして使用できることです。これにより、サード パーティのライブラリ プロバイダー (たとえば、Microsoft や C ランタイムなど) は、ライブラリのバグを修正し、それを配布することができます。エンドユーザーが更新されたDLLをインストールすると、そのDLLを使用するすべてのプログラムでバグ修正の効果がすぐに得られます。(それが何かを破壊しない限り。DLL地獄を参照)。

もうひとつの利点は、暗黙的読み込みと明示的読み込みの区別から来るものです。明示的にロードする余分な努力をした場合、プログラムが書かれ公開されたときに DLL が存在しなかったかもしれません。これにより、たとえば、プラグインを検出してロードする拡張メカニズムが可能になります。