web-dev-qa-db-ja.com

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

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

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

LIBは静的リンク用で、DLLは動的リンク用です。

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

しかし、時々、いくつかのLIBファイルが付属しているDLLファイルなので、

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

アップデート1

ウィキペディアを確認した後、これらのLIBファイルは import library と呼ばれることを覚えています。しかし、メインアプリケーションとDLLがどのように動的にロードされるのか、疑問に思っています。

更新2

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

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

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

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

これでいいの?他に何かありますか?

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

73
smwikipedia

DLLファイルへのリンクは、暗黙的に発生する可能性があります) コンパイル リンク時間、または実行時に明示的に。いずれにしても、DLLはプロセスのメモリ空間に読み込まれ、エクスポートされたエントリポイントはすべてアプリケーションで利用可能になります。

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

プログラムのビルド時に暗黙的にリンクされる場合、プログラムで使用される各DLL exportのスタブはインポートライブラリからプログラムにリンクされ、これらのスタブはEXEおよび= DLLはプロセスの起動時にロードされます。(はい、ここで少しだけ簡略化しました...)

これらのスタブはどこかから取得する必要があり、Microsoftのツールチェーンでは、import libraryと呼ばれる特別な形式の.LIBファイルから取得します。通常、必要な.LIBはDLLと同時にビルドされ、DLLからエクスポートされた各関数のスタブが含まれます。

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

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

更新

すべてのナットとボルトが実際にどこにあり、何が実際に行われているかを知ることに抵抗できない場合は、MSDNに何か役立つものが常にあります。 Matt Pietrekの記事 Win32ポータブル実行可能ファイル形式の詳細な調査 は、 EXEファイルとそれがどのようにロードされ実行されるか。 MSDNマガジンに最初に掲載されて以来、.NETなどをカバーするように更新されました。 2002年。

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

更新2

以前のテキストの一部を書き直して読み直しを明確にし、用語implicitおよびexplicitlinkingMSDNとの一貫性のため。

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

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

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

DLLはすべての機能を含み、すべてのクライアントプログラムで使用できます。多くのプログラムがそのDLLをロードすると、すべてのコードページを共有できます。 DLL=を新しいバージョンで更新しますが、これはこの話の一部ではありません。GoogleDLL物語のあの地獄。)

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

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

もう1つの利点は、暗黙的ロードと明示的ロードの違いにあります。明示的な読み込みの余分な努力をすると、プログラムが作成および公開されたときにDLLは存在しなかったかもしれません。これにより、プラグインを発見して読み込むことができる拡張メカニズムが可能になります。 。

87
RBerteig

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

Linker->Input->Additional Dependencies

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

ただし、これはCommonプロパティーであり、構成またはプラットフォーム固有ではありません。アプリケーションのように混合ビルドシナリオをサポートする必要がある場合、静的ビルドをレンダリングするビルド構成と、動的ライブラリとしてデプロイされたアセンブリのサブセットの制約付きビルドをビルドする特別な構成がありました。さまざまなケースでtrueに設定されたUse Library Dependency InputsおよびLink 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
jxramos

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

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

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

2
zacsek
0
smwikipedia