インポートライブラリはどのように機能しますか?詳細?


90

これはオタクにとってはかなり基本的なことのように思えるかもしれません。しかし、私はそれを明確にしたい。

Win32 DLLを使用する場合、通常はLoadLibrary()やGetProcAdderss()などのAPIを呼び出すだけです。しかし最近、DirectX9で開発しているのでd3d9.libd3dx9.libなどのファイルを追加する必要があります。

LIBは静的リンク用で、DLLは動的リンク用であると十分に聞いています。

したがって、私の現在の理解では、LIBにはメソッドの実装が含まれており、最終的なEXEファイルの一部としてリンク時に静的にリンクされます。DLLは実行時に動的にロードされ、最終的なEXEファイルの一部ではありません。

しかし、時には、いくつかのLIBファイルそこにいると来そう、DLLファイル:

  • これらのLIBファイルは何のためのものですか?
  • 彼らはどのように彼らが意図されていることを達成しますか?
  • これらのLIBファイルの内部を検査できるツールはありますか?

アップデート1

ウィキペディアをチェックした後、これらのLIBファイルはインポートライブラリと呼ばれていることを思い出します。しかし、メインアプリケーションと動的にロードされるDLLでどのように機能するのか疑問に思っています。

アップデート2

RBerteigが言ったように、DLLで生まれたLIBファイルにはいくつかのスタブコードがあります。したがって、呼び出しシーケンスは次のようになります。

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

では、これらのLIBにはどのような情報を含める必要がありますか?私は次のことを考えることができます:

  • LIBファイルには、対応するDLLのフルパスが含まれている必要があります。したがって、DLLはランタイムによってロードされる可能性があります。
  • 各DLLエクスポートメソッドのエントリポイントの相対アドレス(またはファイルオフセット?)は、スタブでエンコードする必要があります。したがって、正しいジャンプ/メソッド呼び出しを行うことができます。

私はこれで正しいですか?他に何かありますか?

ところで:インポートライブラリを検査できるツールはありますか?私がそれを見ることができれば、これ以上の疑いはありません。


4
インポートライブラリを検査できるツールに関する質問の最後の部分については、誰も答えていないようです。Visual C ++では、少なくとも2つの方法があります。lib /list xxx.liblink /dump /linkermember xxx.libこのStackOverflowの質問を参照してください。
アラン

また、およびユーティリティdumpbin -headers xxx.libと比較して、いくつかのより詳細な情報を提供liblinkます。
m_katsifarakis

回答:


105

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の記事 Win32PortableExecutable File Formatの詳細」は、EXEファイルの形式と、そのロードおよび実行方法の非常に完全な概要です。もともとMSDNMagazine caに掲載されて以来、.NETなどをカバーするように更新されています。2002年。

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

アップデート2

以前のテキストの一部を書き直して、読み直しの際に明確にし、MSDNとの一貫性を保つために暗黙的および明示的なリンクの用語を使用しました。

したがって、ライブラリ関数をプログラムで使用できるようにする方法は3つあります。明らかなフォローアップの質問は、「どの方法を選択するか」です。

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

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

ライブラリのDLLには、そのすべての機能が含まれており、クライアントプログラムですぐに使用できます。多くのプログラムがそのDLLをロードする場合、それらはすべてそのコードページを共有できます。誰もが勝ちます。(まあ、DLLを新しいバージョンで更新するまでは、それはこの話の一部ではありません。物語のその側のGoogle DLL地獄。)

したがって、新しいプロジェクトを計画するときに最初に行うべき大きな選択は、動的リンケージと静的リンケージの間です。静的リンケージを使用すると、インストールするファイルが少なくなり、使用するDLLをサードパーティが更新する必要がなくなります。ただし、プログラムはより大きく、Windowsエコシステムの市民としてはそれほど優れていません。ダイナミックリンケージを使用すると、インストールするファイルが増え、使用するDLLをサードパーティが更新する際に問題が発生する可能性がありますが、通常はシステム上の他のプロセスに慣れています。

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

もう1つの利点は、暗黙的ロードと明示的ロードの違いにあります。明示的なロードという余分な労力を費やすと、プログラムが作成および公開されたときにDLLが存在していなかった可能性があります。これにより、たとえばプラグインを検出してロードできる拡張メカニズムが可能になります。


4
私の投稿を削除してこれに賛成するのは、あなたが私よりもうまく説明しているからです;)いい答えです。
ereOn 2010

2
@RBerteig:素晴らしい回答をありがとう。ここ(msdn.microsoft.com/en-us/library/9yd93633.aspx)によると、DLLへの動的リンクには、ロード時の暗黙的なリンク実行時の明示的なリンクの2種類があります。コンパイル時のリンクはありません。従来の静的リンク(完全な実装を含む* .libファイルへのリンク)とDLLへのロード時の動的リンク(インポートライブラリを介した)の違いは何ですか?
smwikipedia 2010

1
続行:静的リンクロード時動的リンクの長所と短所は何ですか?これらの2つのアプローチは両方とも、プロセスの開始時に必要なすべてのファイルをアドレス空間にロードするようです。なぜ2つ必要なのですか?ありがとう。
smwikipedia 2010

1
「objdump」などのツールを使用して、.libファイルの内部を調べ、それがインポートライブラリであるか真の静的ライブラリであるかを判断できます。Linuxでは、Windowsターゲットにクロスコンパイルするときに、.aファイル(.libファイルのmingwバージョン)で「ar」または「nm」を実行できます。インポートライブラリには一般的な.oファイル名があり、コードはありません。 (「jmp」命令のみ)、静的ライブラリには多くの関数とコードが含まれています。
明るいドン

1
小さな修正:実行時に暗黙的にリンクすることもできます。遅延ロードされたDLLのリンカサポートは、これを詳細に説明しています。これは、DLL検索パスを動的に変更したり、インポート解決の失​​敗を適切に処理したりする場合に役立ちます(たとえば、新しいOS機能をサポートしますが、古いバージョンでも実行できます)。
iInspectable 2016

5

これらの.LIBインポートライブラリファイルはLinker->Input->Additional Dependencies、インポートライブラリ.LIBファイルによって提供されるリンク時に追加情報を必要とする一連のdllを構築するときに、次のプロジェクトプロパティで使用されます。以下の例では、リンカーエラーが発生しないように、libファイルを介してdllのA、B、C、およびDを参照する必要があります。(リンカーがこれらのファイルを見つけるために、デプロイメントパスを含める必要がある場合があることに注意してください。Linker->General->Additional Library Directoriesそうしないと、提供されたlibファイルを見つけることができないというビルドエラーが発生します。)

リンカ->入力->追加の依存関係

ソリューションがすべてのダイナミックライブラリを構築している場合は、Common Properties->Framework and Referencesダイアログの下に表示される参照フラグに代わりに依存することで、この明示的な依存関係の指定を回避できた可能性があります。これらのフラグは、*。libファイルを使用してユーザーに代わって自動的にリンクを行うように見えます。 フレームワークとリファレンス

ただし、これは、構成やプラットフォームに固有ではない共通プロパティと呼ばれるとおりです。アプリケーションのように混合ビルドシナリオをサポートする必要がある場合は、静的ビルドをレンダリングするビルド構成と、動的ライブラリとしてデプロイされたアセンブリのサブセットの制約付きビルドをビルドする特別な構成があります。さまざまなケースでtrueに設定されたフラグUse Library Dependency InputsLink Library Dependenciesフラグを使用してビルドを行い、後でそれを単純化することに気づきましたが、静的ビルドにコードを導入すると、大量のリンカー警告が発生し、静的ビルドのビルドは非常に遅くなりました。私はこれらの種類の警告の束を導入することになりました...

warning LNK4006: "bool __cdecl XXX::YYY() already defined in CoreLibrary.lib(JSource.obj); second definition ignored  D.lib(JSource.obj)

そしてAdditional Dependencies、静的ビルダーを遅くする共通のプロパティを使用しないことで静的ビルダーを満足させながら、動的ビルドのリンカーを満たすためにの手動仕様を使用することになりました。ダイナミックサブセットビルドをデプロイするとき、これらのlibファイルは実行時ではなくリンク時にのみ使用されるため、dllファイルのみをデプロイします。


3

ライブラリには、静的ライブラリ、共有ライブラリ、動的にロードされるライブラリの3種類があります。

静的ライブラリはリンクフェーズでコードとリンクされるため、実行時にロードされる共有ライブラリファイルで検索するスタブ(シンボル)のみを持つ共有ライブラリとは異なり、実際には実行可能ファイル内にあります。 main関数が呼び出されます。

動的にロードされるものは、作成したコードによって必要が生じたときにロードされることを除いて、共有ライブラリによく似ています。


@ありがとうzacsek。しかし、共有ライブラリについてのあなたの声明についてはよくわかりません。
smwikipedia 2010

@smwikipedia:Linuxにはそれらがあり、私はそれらを使用しているので、それらは間違いなく存在します。また読み:en.wikipedia.org/wiki/Library_(computingを)
ゾルタンSzőcs

3
その微妙な違い。共有ライブラリとダイナミックライブラリはどちらもDLLファイルです。違いは、それらがいつロードされるかです。共有ライブラリは、EXEとともにOSによってロードされます。ダイナミックライブラリは、コード呼び出しLoadLibrary()と関連するAPIによって読み込まれます。
RBerteig 2010

[1]から、DLLはMicrosoftによる共有ライブラリの概念の実装であると読みました。[1]:en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries
smwikipedia 2010

微妙な違いであることに同意しません。プログラミングの観点から、共有ライブラリが動的にロードされるかどうかにかかわらず、大きな違いが生じます(動的にロードされる場合は、関数にアクセスするために定型コードを追加する必要があります)。
ゾルタンSzőcs

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.