web-dev-qa-db-ja.com

静的ライブラリ(.a)と共有ライブラリ(.so)のファイル形式の違いは?

共有ライブラリと静的ライブラリのユースケースについて多くの質問があることを私は知っていますが、この質問はそれについてではありません。ディスクに保存されているファイル形式の違いについて質問しています。

なぜ質問なのですか、2つの違いは何ですか?それとも、まったく同じで、使用法だけが異なりますか?

共有ライブラリで「nm」を実行するには-Dフラグが必要なため、これらは同じではないと思われます。明らかに、別のことをする必要があります。どうして?

それらは両方ともELFファイルですか?

共有ライブラリに依存関係のパスを含めることができるという唯一の違いはありますか?

12
silverscania

静的ライブラリ、例: libfoo.aはいかなる種類の実行可能ファイルでもありません。これは、たまたま [〜#〜] elf [〜#〜] オブジェクトファイルである他のファイルの nix ar形式 のインデックス付きアーカイブです。

静的ライブラリは、他のアーカイブと同じように作成されます。

ar crs libfoo.a objfile0.o objfile1.0...objfileN.o

新しいアーカイブ(c)libfoo.aを出力し、それらのオブジェクトファイルを挿入(r)し、インデックスを追加(s)します。

プログラムでlinkinglibfoo.aのことを聞くでしょう。これは、libfoo.aitselfがプログラムにリンクされていることを意味するものではありません。これは、libfoo.aがアーカイブとしてリンカーに渡され、そこからプログラムが必要とするアーカイブ内のオブジェクトファイルだけを抽出してプログラムにリンクできることを意味します。したがって、静的ライブラリの形式(ar形式)は、リンカー入力用のオブジェクトファイルのバンドル形式にすぎません。リンカーの使命であるダイジェストに影響を与えることなく、他のバンドル形式である可能性もあります。オブジェクトファイルと共有ライブラリのセットを作成し、それらからプログラムまたは共有ライブラリを生成します。 ar形式は歴史の選択でした。

一方、共有ライブラリ、例えばlibfoo.sois ELFファイルであり、いかなる種類のアーカイブでもありません。

よく知られているすべてのELFパーサー(objdumpreadelfnm)によって、静的ライブラリが一種の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) を試してください。

9
Mike Kinghan

ソース

私の例で使用しているソースコードは次のとおりです。

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

1
OMGtechy

静的ライブラリは、再配置可能なオブジェクトのコレクションにすぎません(ELFではなく、ELFのダミーアーカイブです)。

共有ライブラリは、定義されたインターフェイス(つまり、シンボルテーブル)と依存関係(ELFファイル)を備えたスタンドアロンの機能です。

0
yugr