共有ライブラリと静的ライブラリのユースケースについて多くの質問があることを私は知っていますが、この質問はそれについてではありません。ディスクに保存されているファイル形式の違いについて質問しています。
なぜ質問なのですか、2つの違いは何ですか?それとも、まったく同じで、使用法だけが異なりますか?
共有ライブラリで「nm」を実行するには-Dフラグが必要なため、これらは同じではないと思われます。明らかに、別のことをする必要があります。どうして?
それらは両方ともELFファイルですか?
共有ライブラリに依存関係のパスを含めることができるという唯一の違いはありますか?
静的ライブラリ、例: libfoo.a
はいかなる種類の実行可能ファイルでもありません。これは、たまたま [〜#〜] elf [〜#〜] オブジェクトファイルである他のファイルの nix ar
形式 のインデックス付きアーカイブです。
静的ライブラリは、他のアーカイブと同じように作成されます。
ar crs libfoo.a objfile0.o objfile1.0...objfileN.o
新しいアーカイブ(c
)libfoo.aを出力し、それらのオブジェクトファイルを挿入(r
)し、インデックスを追加(s
)します。
プログラムでlinkinglibfoo.a
のことを聞くでしょう。これは、libfoo.a
itselfがプログラムにリンクされていることを意味するものではありません。これは、libfoo.a
がアーカイブとしてリンカーに渡され、そこからプログラムが必要とするアーカイブ内のオブジェクトファイルだけを抽出してプログラムにリンクできることを意味します。したがって、静的ライブラリの形式(ar
形式)は、リンカー入力用のオブジェクトファイルのバンドル形式にすぎません。リンカーの使命であるダイジェストに影響を与えることなく、他のバンドル形式である可能性もあります。オブジェクトファイルと共有ライブラリのセットを作成し、それらからプログラムまたは共有ライブラリを生成します。 ar
形式は歴史の選択でした。
一方、共有ライブラリ、例えばlibfoo.so
、is ELFファイルであり、いかなる種類のアーカイブでもありません。
よく知られているすべてのELFパーサー(objdump
、readelf
、nm
)によって、静的ライブラリが一種のELFファイルであると疑うことはありません。 -静的ライブラリを解析します。これらのツールはすべて、静的ライブラリがアーカイブであることを認識していますof ELFオブジェクトファイルなので、コマンドラインにリストしたかのように、ライブラリ内のすべてのオブジェクトファイルを解析するだけです。
nm
で-D
オプションを使用すると、解析するELFファイルの動的シンボルテーブルにあるシンボルのみを選択するようにツールに指示するだけです。 -ランタイムリンカーに表示されるシンボル-アーカイブ内から解析されるかどうかに関係なく。 objdump -T
およびreadelf --dyn-syms
と同じです。共有ライブラリからシンボルを解析するには、これらのオプションを使用する必要がありますnot。そうしないと、デフォルトでfullシンボルテーブルが表示されます。静的ライブラリでnm -D
を実行すると、アーカイブ内のオブジェクトファイルごとにno symbols
が通知されます。同様に、これらのオブジェクトファイルごとにnm -D
を個別に実行した場合も同様です。その理由は、オブジェクトファイルに動的シンボルテーブルがないためです。共有ライブラリまたはプログラムのみに動的シンボルテーブルがあります。
オブジェクトファイル、共有ライブラリおよびプログラムはすべてELF形式のバリアントです。 ELFバリアントに興味がある場合は、それらが関心のあるバリアントです。
ELF形式自体は長くて厄介な技術的な読み物であり、バリアントを正確に区別するために必要な背景です。イントロ:ELFファイルにはELFヘッダー構造が含まれ、そのフィールドの1つには、オブジェクトファイル、共有ライブラリ、またはプログラムとしてのファイルのタイプ識別子が含まれます。ファイルがプログラムまたは共有ライブラリの場合、オプションのプログラムヘッダーテーブル構造も含まれます。そのフィールドは、プロセスでファイルをロードするために必要なパラメーターをランタイムリンカー/ローダーに提供します。 ELF構造に関しては、プログラムと共有ライブラリの違いはわずかです。ローダーから引き出す動作に違いをもたらすのは詳細なコンテンツです。
長くて厄介な技術的な読み物については、 Excutable and Linkable Format(ELF) を試してください。
ソース
私の例で使用しているソースコードは次のとおりです。
class T {
public:
T(int _x) : x(_x) { }
T& operator=(const T& rhs) { x = rhs.x; return *this; }
int getX() const { return x; }
private:
int x = 0;
};
共有ライブラリの作成
$ g++ -shared -fPIC -c test.cpp -o test.out && ld -o libtest.so test.out
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
静的ライブラリの作成
$ g++ -fPIC -c test.cpp -o test.out && ar rcs libtest.a test.out
両方ともELFファイルですか?
種類...共有ライブラリのreadelf -h
の出力は次のとおりです。
$ readelf -h libtest.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400078
Start of program headers: 64 (bytes into file)
Start of section headers: 408 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 1
Size of section headers: 64 (bytes)
Number of section headers: 5
Section header string table index: 2
静的ライブラリの出力は非常に似ていますが、まったく同じではありません。
$ readelf -h libtest.a
File: libtest.a(test.out)
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 360 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 9
Section header string table index: 6
最初に飛び出すのは、静的ライブラリのFile
エントリです。 ELFオブジェクトではなく、ELFオブジェクトが含まれています。これを確認する別の方法は、hexdump -C
(切り捨て)のあるファイルを調べることです。まず、共有ライブラリ:
$ hexdump -C libtest.so
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 78 00 40 00 00 00 00 00 |..>.....x.@.....|
00000020 40 00 00 00 00 00 00 00 98 01 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 01 00 40 00 05 00 02 00 |[email protected]...@.....|
00000040 51 e5 74 64 06 00 00 00 00 00 00 00 00 00 00 00 |Q.td............|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000070 10 00 00 00 00 00 00 00 47 43 43 3a 20 28 47 4e |........GCC: (GN|
ここでは、ファイルの先頭にある文字シーケンスELF
を非常にはっきりと見ることができます。静的ライブラリの出力は次のとおりです。
$ hexdump -C libtest.a
00000000 21 3c 61 72 63 68 3e 0a 2f 20 20 20 20 20 20 20 |!<Arch>./ |
00000010 20 20 20 20 20 20 20 20 31 34 38 35 34 36 31 31 | 14854611|
00000020 36 36 20 20 30 20 20 20 20 20 30 20 20 20 20 20 |66 0 0 |
00000030 30 20 20 20 20 20 20 20 34 20 20 20 20 20 20 20 |0 4 |
00000040 20 20 60 0a 00 00 00 00 74 65 73 74 2e 6f 75 74 | `.....test.out|
00000050 2f 20 20 20 20 20 20 20 31 34 38 35 34 36 31 31 |/ 14854611|
00000060 36 36 20 20 31 30 30 30 20 20 31 30 30 30 20 20 |66 1000 1000 |
00000070 31 30 30 36 36 34 20 20 39 33 36 20 20 20 20 20 |100664 936 |
00000080 20 20 60 0a 7f 45 4c 46 02 01 01 00 00 00 00 00 | `..ELF........|
00000090 00 00 00 00 01 00 3e 00 01 00 00 00 00 00 00 00 |......>.........|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 68 01 00 00 |............h...|
000000b0 00 00 00 00 00 00 00 00 40 00 00 00 00 00 40 00 |........@.....@.|
000000c0 09 00 06 00 00 47 43 43 3a 20 28 47 4e 55 29 20 |.....GCC: (GNU)
ELFヘッダーがここで始まる前に、たくさんの余分なものを見ることができます。これは、静的ライブラリが共有ライブラリとは異なる方法で格納されているという仮説を裏付けています。
もう1つの違いは、Type
エントリです。共有ライブラリは実行可能としてマークされますが、静的ライブラリは実行可能としてマークされません。実際、共有ライブラリと実行可能ファイルの間に大きな違いはありません: https://askubuntu.com/questions/690631/executables-vs-shared-objects
静的ライブラリは、再配置可能なオブジェクトのコレクションにすぎません(ELFではなく、ELFのダミーアーカイブです)。
共有ライブラリは、定義されたインターフェイス(つまり、シンボルテーブル)と依存関係(ELFファイル)を備えたスタンドアロンの機能です。