動的リンク-Linux対。ウィンドウズ


10

Windowsでは、MSVCのDLLプロジェクトでC / C ++コードをコンパイルすると、2つのファイルが取得されます。

  1. MyDll.dll
  2. MyDll.lib

私が理解しMyDll.libている限り、DLL内の関数の場所を示すポインタテーブルの種類が含まれています。このdllを使用すると、たとえばexeファイルで、MyDll.libリンケージ時にexeファイルに埋め込まれるため、実行時に関数がどこにあるかを「認識」し、関数MyDll.dllを使用できます。

しかし、Linuxで同じコードをコンパイルすると、1つのファイル(Linuxのファイルに相当)MySo.soなし で1つしか得られないので、リンク時に何も埋め込まれていない場合、Linuxの実行可能ファイルは関数の場所をどのようにして知るのでしょうか。MySo.alibMySo.so

回答:


1

Linuxでは、リンカー(動的リンカーではない)がリンク時に指定された共有ライブラリを検索し、実行可能ファイル内にそれらへの参照を作成します。動的リンカーがこれらの実行可能ファイルをロードすると、必要な共有ライブラリーがメモリーにロードされ、シンボルが解決されるため、バイナリーを実行できます。

MySo.a作成された場合、実際には、Windowsで使用される「シンボルルックアップテーブル」ではなく、バイナリに直接リンクされるシンボルが含まれます。

rustyxの答えは、Windowsでのプロセスを私よりも詳しく説明しています。私がWindowsを使用してから久しぶりです。


1
「Windowsは別のアプローチをとっています...オペレーティングシステムにシンボルがDLLのどこにあるかを正確に指定してください」-これはwikiと矛盾します。序数を使用します(ライブラリが変更されるたびにライブラリユーザーがコードを再コンパイルして再デプロイする必要があるため、誰もしない直接アドレスバインディングが使用される場合を除く)。
yugr

@yugrその部分を外して、とにかくストローを掴んでいた。
SSアン、

4

MSVCリンカーは、オブジェクトファイル(.obj)とオブジェクトライブラリ(.lib)をリンクして、.EXEまたは.DLLを生成できます。

DLLとリンクするには、MSVCでのプロセスは、C関数名とDLLのエクスポートテーブルの間の接着剤として機能するいわゆるインポートライブラリ(.LIB)を使用することです(DLLでは、関数は名前またはで -後者は、多くの場合、文書化されていないのAPIを使用しました)。

ただし、ほとんどの場合、DLLエクスポートテーブルにはすべての関数名があるため、インポートライブラリ(.LIB)には大部分が冗長な情報( " インポート関数ABC->エクスポート関数ABC "など)が含まれています。既存の.DLLから.LIB
生成することも可能です。

他のプラットフォームのリンカーにはこの「機能」がなく、ダイナミックライブラリに直接リンクできます。


「他のプラットフォームのリンカーにはこの機能はありません」-実装を簡単にして(たとえば、Implib.soがLinuxでこれを行う)、遅延ロードやその他の機能を実現できます。
yugr

@yugr:これが、「機能」が引用符で囲まれている理由です。これは、通常、実行したいことではなく、Windowsで実行する必要がある追加の作業です。
クリス・ドッド

1

あなたが見ている違いは実装の詳細です-LinuxとWindowsの両方のフードの下で同じように動作します-あなたは実行可能ファイルに静的にリンクされたスタブ関数をコード呼び出しし、このスタブは必要に応じてDLL / shlibをロードします(遅延の場合)ロード、そうでなければライブラリはプログラムの起動時にロードされます)および(最初の呼び出しで)GetProcAddress/ を介してシンボルを解決しdlsymます

唯一の違いは、Linux上で(PLTスタブと呼ばれている)これらのスタブ関数が生成されるということである動的動的ライブラリを使用してアプリケーションをリンクするときに、Linux上で、彼らが代わりに生成されているのに対し、DLL自体である場合には、(ライブラリはそれらを生成するために十分な情報が含まれています)別の.libファイルに作成されます。

2つのアプローチは非常に似ているため、LinuxでWindowsインポートライブラリを模倣することが実際に可能です(Implib.soプロジェクトを参照)。


0

Linuxでは、MySo.soリンカーに渡すと、リンク段階に必要なものだけを抽出MySo.soして、実行時に必要な参照を入れることができます。


-3

.dllまたは.so一方で、(実行時にリンク)LIBSを共有している.aと、.lib静的ライブラリ(コンパイル時にリンク)があります。これはWindowsとLinuxの違いではありません。

違いは、それらがどのように処理されるかです。注:違いは税関のみで、どのように使用されているかです。LinuxをWindowsでビルドしたり、その逆を行ったりすることは、実際に誰もこれを行わないことを除いて、それほど難しくありません。

dllを使用する場合、または独自のバイナリからでも関数を呼び出す場合、シンプルで明確な方法があります。たとえば、Cでは次のようになります。

int example(int x) {
  ...do_something...
}

int ret = example(42);

ただし、asmレベルでは、多くの違いがある可能性があります。たとえば、x86では、callオペコードが実行さ42れ、スタックに与えられます。または一部のレジスター。またはどこでも。dllを作成する前に、それがどのように使用されるか誰にもわかりません。または、プロジェクトがそれをどのように使用するか、現在では存在しない(またはdllの開発者にとっては不明な)コンパイラー(または言語で!)

たとえば、デフォルトでは、CとPascalの両方が引数をスタックから(そして戻り値を)取得しますが、それらは異なる順序で実行されます。コンパイラー依存の最適化によって、レジスター内の関数間で引数を交換することもできます。

ご覧のとおり、Windowsのカスタムはdllを構築することであり、最小限の.a/ .libを作成します。この最小限の静的ライブラリはラッパーにすぎず、そのdllのシンボル(関数)はそこから到達します。これにより、必要なasmレベルの呼び出し変換が行われます。

その利点は互換性です。その不利な点は、.dllしかない場合、その関数の呼び出し方法を理解するのに苦労する可能性があることです。これにより、DLL の開発者から提供されない場合に、.a DLLの使用がハッキングタスクになります。したがって、これは主にクローズドな目的に役立ちます。たとえば、SDKの追加の現金をより簡単に取得できます。

そのもう1つの欠点は、動的ライブラリを使用する場合でも、この小さなラッパーを静的にコンパイルする必要があることです。

Linuxでは、dllのバイナリインターフェイスは標準で、Cの規則に従っています。したがって、.a必要なものはなく、共有ライブラリ間にはバイナリ互換性がありますが、マイクロソフトカスタムの利点はありません。


1
スタブ関数が引数の順序を変更できることを証明するリンクを提供してください。これについて聞いたことがなく、パフォーマンスのオーバーヘッドがどれほど大きいかを考えると、信じられません。
yugr

@yugr単純なレジスタ/スタックの並べ替えは、パフォーマンスのオーバーヘッドではありません。msvcでコンパイルされたバイナリからmsvcでコンパイルされたdllを使用する場合、明らかにそれほど多くは起こりませんが、それは可能です。
peterh

1
これについては議論することもできますが、あなたが正しい場合は、スタブ関数が引数の重要な処理に対応している(そして単なるダミーのトランポリン以上のものである)証明リンクを提供するのは簡単です。
yugr

@yugrスタブはdllの関数シグネチャにアクセスできるため、重要な処理が簡単になります。
peterh

1
インポートライブラリの機能に関するいくつかの証明リンクを使用して回答を完成させることをお勧めします(一部の主張には疑問があるため)。
yugr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.