32

共有 object( .so) ファイルと object( .o) ファイルの関係は?

例を挙げて説明していただけますか?

4

2 に答える 2

83

次の C ソース ファイルがあるとします。name.c

#include <stdio.h>
#include <stdlib.h>

void print_name(const char * name)
{
    printf("My name is %s\n", name);
}

コンパイルすると、cc name.cが生成されname.oます。.o には、name.c で定義されたすべての関数と変数のコンパイル済みコードとデータ、およびそれらの名前と実際のコードを関連付けたインデックスが含まれています。nmツール (Linux および他の多くの Unix で利用可能) を使用してそのインデックスを調べると、次の 2 つのエントリに気付くでしょう。

00000000 T print_name
         U printf

これが意味すること: .o. には 2 つのシンボル (関数または変数の名前であり、クラス、構造体、または型の名前ではない) が格納されています。でマークされた最初のものには、T実際にはその定義がに含まれていますname.o。もう一方の でマークされてUいるものは、単なる参照です。のコードはprint_nameここにありますが、のコードは見つかりprintfません。実際のプログラムを実行すると、完全なプログラムまたは完全なライブラリにリンクするために、参照であるすべてのシンボルを見つけ、他のオブジェクト ファイルでそれらの定義を検索する必要があります。したがって、オブジェクト ファイルは、ソース ファイルで検出された定義であり、バイナリ形式に変換され、完全なプログラムに配置するために使用できます。

.o ファイルを 1 つずつリンクすることはできますが、リンクすることはできません。通常、それらは多数あり、それらは実装の詳細です。それらをすべて、よく知られている名前を付けて、関連するオブジェクトのバンドルにまとめたいと思うでしょう。これらのバンドルはライブラリと呼ばれ、静的と動的の 2 つの形式があります。

静的ライブラリ(Unixの場合) には、ほとんどの場合、( C コア ライブラリである、C 数学ライブラリであるなどの.a例が含まれます) などの接尾辞が付いています。で静的ライブラリを構築する例を続けます。実行すると、次のように表示されます。libc.alibm.aar rc libname.a name.onmlibname.a

name.o:
00000000 T print_name
         U printf

ご覧のとおり、これは主にオブジェクト ファイルの大きなテーブルであり、その中のすべての名前を検索するインデックスが付いています。オブジェクト ファイルと同様に、every.oで定義されたシンボルとそれらによって参照されるシンボルの両方が含まれます。別の.o (たとえばdate.oへ)にリンクするとprint_date、上記のような別のエントリが表示されます。

静的ライブラリを実行可能ファイルにリンクすると、ライブラリ全体が実行可能ファイルに埋め込まれます。.oこれは、すべての個々のファイルをリンクするのと同じです。ご想像のとおり、これによりプログラムが非常に大きくなる可能性があります。特に (ほとんどの最新のアプリケーションがそうであるように) 多くのライブラリを使用している場合はそうです。

動的ライブラリまたは共有ライブラリには、接尾辞が付きます。これは、静的な類似物と同様に、コンパイルされたすべてのコードを参照するオブジェクト ファイルの大きなテーブルです。でビルドします。ただし、 with を見ると、静的ライブラリとはかなり異なります。私のシステムでは、約2ダースの記号が含まれており、そのうちの2つだけがandです。.socc -shared libname.so name.onmprint_nameprintf

00001498 a _DYNAMIC
00001574 a _GLOBAL_OFFSET_TABLE_
         w _Jv_RegisterClasses
00001488 d __CTOR_END__
00001484 d __CTOR_LIST__
00001490 d __DTOR_END__
0000148c d __DTOR_LIST__
00000480 r __FRAME_END__
00001494 d __JCR_END__
00001494 d __JCR_LIST__
00001590 A __bss_start
         w __cxa_finalize@@GLIBC_2.1.3
00000420 t __do_global_ctors_aux
00000360 t __do_global_dtors_aux
00001588 d __dso_handle
         w __gmon_start__
000003f7 t __i686.get_pc_thunk.bx
00001590 A _edata
00001594 A _end
00000454 T _fini
000002f8 T _init
00001590 b completed.5843
000003c0 t frame_dummy
0000158c d p.5841
000003fc T print_name
         U printf@@GLIBC_2.0

共有ライブラリは、1 つの非常に重要な点で静的ライブラリと異なります。それは、最終的な実行可能ファイルに自分自身を埋め込まないことです。代わりに、実行可能ファイルには、リンク時ではなく実行時に解決される共有ライブラリへの参照が含まれています。これには多くの利点があります。

  • 実行可能ファイルははるかに小さくなります。オブジェクトファイルを介して明示的にリンクしたコードのみが含まれています。外部ライブラリは参照であり、そのコードはバイナリには含まれません。
  • 複数の実行可能ファイル間で 1 つのライブラリのビットを共有できます (名前の由来)。
  • バイナリ互換性に注意している場合は、プログラムの実行の間にライブラリ内のコードを更新できます。プログラムは、変更する必要なく新しいライブラリを取得します。

いくつかの欠点があります。

  • プログラムをリンクするには時間がかかります。共有ライブラリを使用すると、実行可能ファイルが実行されるたびにこの時間の一部が延期されます。
  • プロセスはより複雑です。共有ライブラリ内のすべての追加シンボルは、実行時にライブラリをリンクするために必要なインフラストラクチャの一部です。
  • ライブラリの異なるバージョン間で微妙な非互換性が生じるリスクがあります。Windows では、これは「DLL 地獄」と呼ばれます。

(考えてみれば、これらの多くは、プログラムがクラスのオブジェクトを他のオブジェクトに直接埋め込む代わりに、参照やポインターを使用する、または使用しない理由です。類推は非常に直接的です。)

わかりました、それは多くの詳細であり、リンクプロセスが実際にどのように機能するかなど、多くをスキップしました. フォローしていただけると幸いです。そうでない場合は、説明を求めてください。

于 2009-07-31T05:55:53.370 に答える