Windows共有ライブラリ(DLL)とLinux共有ライブラリ(SO)について簡単な質問があります。
Windowsを作成するときにDLLはクライアントプログラムが静的ライブラリ(.libファイル)に対してもリンクする必要があるが、Linuxで作成されたアプリケーションはそのような静的に対してリンクする必要がないのはなぜですか?図書館。
コードの再配置などと関係がありますか?ありがとう。
実際にはコードの再配置ではなく、まったく別の問題です。アーキテクチャの違いについてです:
Windowsでは、DLLは実行可能ファイル(EXE)のようです。EXEとDLLの主な違いは、EXEにエントリポイントがあることです( main/WinMain関数)を使用してプロセスを開始できますが、DLLは既存のプロセスにのみロードできます。ただし、(1)を参照してください。
Linuxでは、.soは静的ライブラリ(.a)と同様に機能します。主な違いは、.soファイルは実行中のプログラムとリンクできるのに対し、.aファイルはプログラムのコンパイル時にのみリンクできることです。
このアプローチの結果として、Linuxでは同じファイルを使用してプログラムを構築および実行できます。ただし、Windowsでは、プログラムをリンクするための適切なライブラリ(LIB)が必要です。実際には、DLLに対応するlibには通常、リンカを満たすための関数の名前と、再配置を行うためのスタブしかありません。しかし、(2)を参照してください。
(1)まあ、DLLにもエントリポイントがありますが、それはある種の初期化/終了フックと同じように、メイン関数としては使用されません。
(2)一部のリンカは、いくつかの単純なケースでは、DLL自体を使用することにより、DLL自体を使用することなく、追加のLIBファイル少なくともMinGWリンカがそれを実行できると思います。
Windows DLLを作成するときに、クライアントプログラムが静的ライブラリ(.libファイル)にもリンクする必要があるのに、Linuxで作成されたアプリケーションはそのような静的ライブラリに対するリンクを必要としないのはなぜですか。
これは、リンク時に特定のバージョンのDLLが存在しなくても、リンカがDLL参照を実行可能ファイルに追加できるように、Microsoftが行った歴史的な設計上の決定です。これは、DLLのバージョンが異なるWindowsのバージョンが常に異なるためです。また、当時MicrosoftはOS/2でIBMと協力しており、WindowsプログラムもOS/2で実行できるようにする計画でした。マイクロソフトは、NTカーネルに基づいて、独自のプロフェッショナルグレードのOSを導入することにより、OS/2を「バックスタブ」することを決定しました。しかし、これは、開発のために、DLLのさまざまなバリアントをすべて利用可能にすることなく、開発者がシステムDLLにリンクできることを望んでいたことを意味しました。代わりに、ダイナミックリンケージ「テンプレート」を使用して、DLLと実行可能ファイル(どちらもPE形式)を作成します。これらは、特定の.lib
ファイルであり、ライブラリではありません。すべて、ただしシンボルと序数のテーブルのみです(これはあまり知られていない事実ですが、PEバイナリシンボルは、文字列識別子だけでなく、整数(いわゆる序数)によってもロードできます)。
序数の副作用は、人間が読める記号を隠すことができるため、序数←→関数の関係を知っている場合にのみDLLを使用できることです。
Unixの伝統は"実行するシステムでビルドする"、または"すべてのターゲットシステムファイルが配置されている"です。したがって、インセンティブがなかったため、ライブラリとリンケージの情報は別になりました。技術的にはDLLでも同じように機能します。 PEはDLLが行うように、シンボルと再配置テーブルをエクスポートできます。リンカーは、そこから必要なすべての情報を取得できます。
Unix共有オブジェクトでシンボルを非表示にする場合は、通常、すべての関数ポインターを含む単一のstruct
を使用し、この構造体のグローバル定数インスタンスのみを名前でエクスポートします。明示的に名前が付けられていない多くのポインタ。ただし、Windows DLLでもまったく同じことができます。
TL; DR:これの理由は技術的なものではなく、マーケティングと流通の決定に関するものです。
Windowsでは、クライアントプログラムは、DLLの関数にアクセスするために静的ライブラリとリンクする必要はありません。動的リンクは、コンパイル時にクライアントプログラムがDLLの存在を認識していなくても、実行時に完全に発生する可能性があります。
たとえば、「foo.dll」という名前のDLLで関数名「foo」を呼び出したい場合、次のようなコードを書くことができます。
HINSTANCE hinst = LoadLibrary("bar.dll");
FARPROC foo = GetProcAddress(hinst, "foo");
foo();
そして、 "foo"と "bar.dll"は、構成ファイルや他のユーザー入力などによって、実行時にのみ確立される値である可能性が高いです。
静的ライブラリの目的は、クライアントプログラムに関する限り通常の関数のように見えるが、実行時にDLLにリンクされる)スタブを作成することにより、この動的ロードプロセスを自動化することです。通常、このリンクはクライアントプロセスのロード時に行われますが、オンデマンドでロードおよびリンクするライブラリを生成することもできるため、DLLはメモリに読み込まれるまで読み込まれません。リンクが発生するタイミングを決定するのは静的ライブラリです。
ほとんどの場合、コンパイラーはこれらのライブラリーを自動的に生成できるため、技術的にはDLL関数にリンクするだけでは必要ありません。ただし、これに対する1つの例外(私が知っていること) )は、共有変数にリンクする場合です。
Windowsでは、DLL DLLをロードした任意のプロセスがアクセスできる変数を使用して共有データセグメントを作成できます。これらの変数のサイズとタイプに関する情報は、関連するDLLだけでは判断できません。これらの変数にアクセスするには、クライアントプログラムがそのDLLの静的ライブラリにリンクする必要があります。
私の知る限り、Linux共有ライブラリはそのような概念をサポートしていません。
更新
また、Windowsでは、DLLを作成することが可能であり、関数のエントリポイントが名前ではなく序数(数値)でのみエクスポートされることも可能です。これは、データを隠す形式と考えることができます。また、通常、実装者が特定の機能を非公開にしたい場合に使用されます。
ライブラリには関数名を適切な序数にリンクする詳細があるため、静的ライブラリにアクセスできるユーザーは、これらの関数を名前で呼び出すことができます。 DLLしかない場合は、序数で関数に手動でリンクするか、名前を付けて独自の静的ライブラリを生成する必要があります。