web-dev-qa-db-ja.com

C / C ++ダイナミックリンクはさまざまなプラットフォームでどのように機能しますか?

ダイナミックリンクは一般的にどのように機能しますか?

Windows(LoadLibrary)では、実行時に呼び出すために.dllが必要ですが、リンク時に、対応する.libファイルを提供する必要があります。そうしないと、プログラムはリンクしません... .libファイルには何が含まれていますか? .dllメソッドの説明?それはヘッダーに含まれているものではありませんか?

関連して、* nixでは、libファイルは必要ありません...ヘッダーに記述されているメソッドが実行時に使用可能になることをコンパイラーはどのようにして知るのでしょうか。

初心者として、2つのスキームのいずれか、次にもう一方について考えるとき、どちらも意味がありません...

26
Charlie

質問に1つずつ答えるには:

  • ダイナミックリンクは、リンクプロセスの一部をランタイムに延期します。暗黙的および明示的に2つの方法で使用できます。暗黙的に、静的リンカーは実行可能ファイルに情報を挿入します。これにより、ライブラリが必要なシンボルをロードして解決します。明示的には、手動でLoadLibraryまたはdlopenを呼び出してから、使用する必要のあるシンボルごとにGetProcAddress/dlsymを呼び出す必要があります。暗黙的なロードは、実装がシステムのバージョンに依存するシステムライブラリなどに使用されますが、インターフェイスは保証されています。明示的なロードは、プラグインなどに使用されます。プラグインでは、ロードされるライブラリが実行時に決定されます。

  • .libファイルは、暗黙的なロードにのみ必要です。ライブラリが実際にこのシンボルを提供するという情報が含まれているため、リンカーはシンボルが未定義であると文句を言うことはなく、シンボルがどのライブラリにあるかをリンカーに通知するため、このライブラリに必要な情報を挿入できます。自動的にロードされます。すべてのヘッダーファイルは、シンボルがどこかに存在することをコンパイラに通知します。リンカは、場所を知るために.libを必要とします。

  • Unixでは、すべての情報は.soから抽出されます。 Windowsがすべての情報を1つのファイルに入れるのではなく、2つの別々のファイルを必要とする理由はわかりません。 .libで必要な情報は.dllでも必要であるため、実際にはほとんどの情報が複製されています。 (おそらくライセンスの問題です。プログラムは.dllで配布できますが、.libがない限り、誰もライブラリにリンクできません。)

保持する主なことは、暗黙的なロードが必要な場合は、リンカーに.libまたは.soファイルのいずれかで適切な情報を提供して、その情報をに挿入できるようにする必要があるということです。実行可能。また、明示的な読み込みが必要な場合は、ライブラリ内のシンボルを直接参照することはできません。自分でアドレスを取得するには、GetProcAddress/dlsymを呼び出す必要があります(そして、それらを使用するには、面白いキャストを行う必要があります)。

22
James Kanze

.libファイルはダイナミックライブラリをロードするために必要ではありません、それはそうするための便利な方法を提供するだけです。

原則として、 LoadLibrary を使用してdllをロードし、GetProcAddressを使用してそのdllが提供する関数にアクセスできます。その場合、囲んでいるプログラムのコンパイルはdllにアクセスする必要はなく、実行時(つまり、LoadLibraryが実際に実行されるとき)にのみ必要です。 MSDNには コード例 があります。

ここでの欠点は、dllから関数をロードするためのコードを手動で作成する必要があることです。そもそも自分でdllをコンパイルした場合、このコードは、コンパイラがdllソースコードから自動的に抽出した可能性のある知識(エクスポートされた関数の名前や署名など)を複製するだけです。

これが.libファイルの内容:コンパイラによって生成されたDLLエクスポート関数のGetProcAddress呼び出しが含まれているため、心配する必要はありません。 Windowsの用語では、これは Load-Time Dynamic Linking と呼ばれます。これは、Dllがからのコードによって自動的にロードされるためです。囲んでいるプログラムがロードされたときのlibファイル(手動のアプローチとは対照的に、ランタイムダイナミックリンクと呼ばれます)。

13
ComicSansMS

ダイナミックリンクは一般的にどのように機能しますか?

ダイナミックリンクライブラリ(別名共有オブジェクト)ファイルには、マシンコードの命令とデータ、およびそのコード/データのどのオフセットがどの「シンボル」、シンボルのタイプ(関数とデータなど)に関連するかを示すメタデータのテーブルが含まれています。データ内のバイトまたはワードの数、およびその他のいくつかのこと。 OSが異なれば、共有オブジェクトファイル形式も異なる傾向があり、実際、同じOSが複数をサポートする可能性がありますが、それがその要点です。

したがって、共有ライブラリが次のようなインデックスを持つバイトの大きなチャンクであると想像してください。

_SYMBOL       ADDRESS        TYPE        SIZE
my_function  1000           function    2893
my_number    4800           variable    4
_

一般に、シンボルの正確なタイプをメタデータテーブルにキャプチャする必要はありません。ライブラリのヘッダーファイルの宣言には、不足しているすべての情報が含まれていると予想されます。 C++は、たとえばCと比較して、少し特殊です。オーバーロードは、同じ名前の関数が複数存在することを意味する可能性があり、名前空間では、あいまいな名前が付けられる可能性のあるシンボルをさらに追加できるためです。そのため、name mangling is通常、名前空間と関数引数の表現を関数名に連結して、ライブラリオブジェクトファイル内で一意にすることができるものを形成するために使用されます。

共有オブジェクトを使用したいプログラムは、通常、次の2つのいずれかを実行できます。

  • oSがそれ自体と共有オブジェクトの両方をほぼ同時に(main()を実行する前に)ロードし、OSローダーがシンボルの検索とそれらのシンボルの使用に関するプログラムファイルイメージ内のメタデータの調査を担当します。次に、プログラムが使用するメモリ内のシンボルアドレスにパッチを適用します。これにより、プログラムは、最初にコンパイルされたときにシンボルアドレスについて知っていたかのように実行され、機能的に動作します(ただし、少し遅くなります)。

  • または、独自のソースコードで明示的にdlopenの実行後にmainを呼び出し、dlsymなどを使用してシンボルアドレスを取得し、(関数/データ)ポインタに保存します予想されるデータ型に関するプログラマーの知識に基づいて、ポインターを使用して明示的に呼び出します。

Windows(LoadLibrary)では、実行時に呼び出すために.dllが必要ですが、リンク時に、対応する.libファイルを提供する必要があります。そうしないと、プログラムはリンクしません...

それは正しく聞こえません。どちらかだと思います。

.libファイルにはWtfが含まれていますか? .dllメソッドの説明?それはヘッダーに含まれているものではありませんか?

Libファイルは、このレベルの説明では、共有オブジェクトファイルとほとんど同じです...主な違いは、プログラムが出荷されて実行される前に、コンパイラがシンボルアドレスを検出することです。

9
Tony Delroy

関連して、OS X(そして私は* nix ... dlopenを想定しています)では、libファイルは必要ありません...ヘッダーに記述されているメソッドが実行時に利用可能になることをコンパイラーはどのように知るのですか?

コンパイラまたはリンカはそのような情報を必要としません。プログラマーであるあなたは、dlopen()によって開こうとしている共有ライブラリーが存在しない可能性がある状況に対処する必要があります。

2
Lee Duhem

WindowsでDLLファイルを使用するには、次の2つの方法があります。リンクするだけで完了です。または実行時に動的にロードします。

リンクすると、DLLライブラリファイルが使用されます。link-libraryには、リンカが実際にどのDLLをロードし、ここで、DLL関数は、それらを呼び出すことができます。プログラムがロードされると、オペレーティングシステムもDLLをロードします。基本的には、 LoadLibraryを呼び出しますか。

他のオペレーティングシステム( OS X やLinuxなど)でも同様に機能します。違いは、これらのシステムでは、リンカがダイナミックライブラリ(.so/.dynlib file)そして、Windowsのように別個の静的ライブラリなしで何が必要かを理解します。

ライブラリを動的にロードするために、ロードするライブラリに関連するものとリンクする必要はありません。

最新の* nixシステムは、SolarisOSから動的リンクのプロセスを派生させます。特にLinuxでは、すべての外部依存関係がELF形式で含まれているため、個別の.libファイルは必要ありません。 ELFファイルの.interpセクションは、動的に解決する必要のある外部シンボルがこの実行可能ファイル内にあることを示しています。これはダイナミックリンクのために来ます。

ユーザースペースでダイナミックリンクを処理する方法があります。このメソッドは動的ロードと呼ばれます。これは、システムコールを使用して、外部* .soからメソッドへの関数ポインターを取得する場合です。

詳細については、この記事 http://www.ibm.com/developerworks/library/l-dynamic-libraries/ を参照してください。

2
mesmerizingr

他の人がすでに言ったように:Windowsの.libファイルに含まれているものは、Linuxの.so/.dynlibに直接含まれています/ OS X 。しかし、主な質問は...なぜですか? * nixソリューションの方が優れているのではないですか?そうだと思いますが、.libには1つの利点があります。 DLLにリンクしている開発者は、実際にはDLLファイル自体にアクセスする必要はありません。

そのようなシナリオは現実の世界で頻繁に発生しますか? DLLファイルごとに2つのファイルを維持する努力をする価値はありますか?わかりません。

編集:わかりました、みんなは物事をさらに混乱させましょう! MinGWを使用して、WindowsのDLLに直接リンクできます。したがって、インポートライブラリの問題全体は直接関連していませんWindows自体に。 sampleDLL MinGW wikiの記事から引用:

「--out-implib」リンカーオプションによって作成されたインポートライブラリは、DLLが、MinGW以外のC/C++コンパイラからインターフェイスされる場合にのみ)必要です。ツールチェーン。MinGWツールチェーンは、作成されたDLLに対して直接リンクできます。詳細については、binutilsパッケージ(ツールチェーンの一部)の一部であるld.exe情報ファイルを参照してください。

2
cubuspl42

Linuxもリンクする必要がありますが、代わりに.Libライブラリに対して動的リンカーにリンクする必要があります/lib/ld-linux.so.2ですが、これは通常、GCCを使用するときに舞台裏で発生します(ただし、アセンブラーを使用する場合は、手動で指定する必要があります)。

Windows .LIBアプローチまたはLinux動的リンカーリンクアプローチのどちらのアプローチも、実際には静的リンクと見なされます。ただし、Windowsでは、ロード時にまだ作業が行われているにもかかわらず、作業の一部がリンク時に行われるという違いがあります(わかりませんが、.LIBファイルはリンカーが物理を知るためだけのものだと思いますただし、ライブラリ名、シンボルはロード時にのみ解決されます)が、Linuxでは、ダイナミックリンカーへのリンク以外のすべてがロード時に発生します。

ダイナミックリンクは、一般に、実行時にDLLファイルを手動で開く(LoadLinrary()を使用するなど))ことを指します。この場合、負担は完全にプログラマーにあります。

1
yoel halb

_.dll_ _.dylib_や_.so_などの共有ライブラリには、次のようなシンボルの名前とアドレスに関する情報があります。

_------------------------------------
| symbol's name | symbol's address |
|----------------------------------|
| Foo           | 0x12341234       |
| Bar           | 0xabcdabcd       |
------------------------------------
_

また、LoadLibrarydlopenなどのロード関数は、共有ライブラリをロードして使用できるようにします。

GetProcAddressdlsymはシンボルのアドレスを見つけます。例えば:

_HMODULE shared_lib = LoadLibrary("asdf.dll");
void *symbol = GetProcAddress("Foo");
// symbol is 0x12341234
_

Windowsには、_.lib_を使用するための_.dll_ファイルがあります。この_.lib_ファイルにリンクするときは、LoadLibraryGetProcAddressを呼び出す必要はなく、共有ライブラリの関数を「通常の」関数であるかのように使用するだけです。どのように機能しますか?

実際、_.lib_にはインポート情報が含まれています。そのようなものです:

_void *Foo; // please put the address of Foo there
void *Bar; // please put the address of Bar there
_

オペレーティングシステムがプログラムをロードすると(厳密に言えば、モジュール)、オペレーティングシステムはLoadLibraryGetProcAddressを自動的に実行します。

また、Foo();などのコードを作成すると、コンパイラーはそれを自動的に_(*Foo)();_に変換します。したがって、それらを「通常の」機能であるかのように使用できます。

0
ikh