2009-07-31 11 views

答えて

2

.soは、Windowsの.dllに似ています。 A .oはVisual Studioの.objとまったく同じです。

65

あなたがname.oを生成cc name.cで、あなたはそれをコンパイルするとname.c

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

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

それを呼び出す、あなたは以下のCソースファイルがあるとしましょう。 .oには、name.cで定義されたすべての関数と変数のコンパイル済みコードとデータ、および実際のコードと名前を関連付けたインデックスが含まれています。あなたはそのインデックスを見れば、(Linuxや他の多くのUnix上で利用可能)nmツールを使用すると、2つのエントリ気づく言う:

00000000 T print_name 
     U printf 

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

.oファイルを1つずつリンクすることはできますが、そうではありません。一般的には多くあり、実装の詳細です。あなたは、それらを全てよく関連するオブジェクトの束に集めて、よく知られた名前にしたいと思っています。これらのバンドルは、ライブラリと呼ばれ、スタティックとダイナミックの2つの形式があります。 (UNIXの場合)

スタティックライブラリはほとんど常にように.a接尾辞(例としては、C数学ライブラリであるCコアライブラリ、libm.aあるlibc.aを含む)とされています。この例を続けると、スタティックライブラリをar rc libname.a name.oで構築します。あなたは、それは主にそれですべての名前を見つけるインデックスを持つオブジェクトファイルの大きなテーブルで見ることができるように

name.o: 
00000000 T print_name 
     U printf 

:あなたはlibname.anmを実行する場合は、これを参照してくださいよ。オブジェクトファイルと同様に、.oに定義されているシンボルとそれが参照するシンボルの両方が含まれています。 .o(例:date.o〜)にリンクする場合は、上記のような別のエントリが表示されます。

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

動的又は共有ライブラリ.soでサフィックスされます。静的なアナログのように、コンパイルされたすべてのコードを参照するオブジェクトファイルの大きなテーブルです。 cc -shared libname.so name.oでビルドします。 nmで見ることは静的ライブラリとはかなり異なっています。

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 [email protected]@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 [email protected]@GLIBC_2.0 

共有ライブラリが1つの非常に重要な方法で静的ライブラリと異なります:それはあなたの最終的な実行可能ファイル自体に埋め込まれません。私のシステムではそれがprint_nameprintfをしている2つだけそのうち約2ダースの記号が含まれています。実行可能ファイルには、リンク時ではなく実行時に解決される共有ライブラリへの参照が含まれています。これにはいくつかの利点があります。

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

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

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

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

これは非常に細かいことですが、リンク処理が実際にどのように機能するかなど、私はずっとスキップしました。あなたがそれに従うことを願っています。明確化を求めない場合。

+8

共有ライブラリはプラグインを実装する一般的な方法です。プラグインは、アプリケーション機能を変更せずに拡張する方法です。アプリケーションは、ライブラリへのパスをdlopen()に呼び出し、ライブラリ内の特定のシンボル(関数など)を見つけるためにdlsym()を呼び出して共有ライブラリをロードできます。ライブラリから機能を実行する関数へのアプリケーション呼び出し。 – dimba

+1

読み込みとリンクの世界への素晴らしい紹介:) +1 – xtofl

+0

素敵な説明:) +1 –

関連する問題