5. 雑録

5.1. nm コマンド

nm(1) コマンドは、与えられたライブラリ内のシンボルのリストを報告します。 静的ライブラリ、共有ライブラリのどちらに対しても機能します。 nm(1) は与えられたライブラリで定義されているシンボル名、シンボルの値、 シンボルのタイプを表示します。また、そのライブラリ内に情報が存在するならば (-l オプションを見てください) 、シンボルがソースコード内のどこで (ファイル名と行番号) 定義されているかということも特定できます。

シンボルタイプについてはもう少し説明が必要です。 タイプは一文字で表示されます。小文字はそのシンボルがローカルであることを意味し、 大文字はそのシンボルがグローバル (外部) であることを意味します。 典型的なシンボルのタイプは次のものを含みます―― T (コードセクション内の普通の定義) D (初期化されたデータセクション) B (初期化されていないデータセクション) U (未定義。シンボルはライブラリによって使われているが、 ライブラリ内では定義されていない) W (weak. もしも他のライブラリもこのシンボルを定義していた場合、 その定義がオーバーライドする)

関数の名前は覚えているけれども、 それがどのライブラリで定義されているか正確には思い出せない場合、 ライブラリ名を見つけるため、nm の ``-o'' オプション (各ラインのファイル名の前に置きます) に grep を続けて使うことができます。 Bourne シェルであれば、/lib, /usr/lib, /usr/lib の直下のサブディレクトリ、 および /usr/local/lib 内の全ライブラリを対象にして ``cos'' を検索するには、 次のようにします――
nm -o /lib/* /usr/lib/* /usr/lib/*/* \
      /usr/local/lib/* 2> /dev/null | grep 'cos$' 

nm に関するもっと多くの情報は、 info:binutils#nm にローカルにインストールされている nm の ``info'' ドキュメントで得られます。

5.2. 特別な関数 _init と _fini

二つの特別な関数 _init と _fini は、モジュールの初期処理と終了処理を支援します。 もしもライブラリ内で関数 ``_init'' がエクスポートされていると、 そのライブラリのオープン時に dlopen() が呼ばれるたび、 その関数が呼び出されます。 C のプログラムでは、_init という名前の関数を定義することを意味します。 これに対応する _fini と呼ばれる関数も存在し、 これは、クライアントがライブラリの解放時に dlclose() を呼ぶたびに、呼び出されます (そして解放されます) 。 これらの関数の C プロトタイプは次のようになっています。
  void _init(void);
  void _fini(void);

Gcc でファイルを ``.o'' ファイルへとコンパイルするときは、 忘れずに ``-nostartfiles'' オプションを付けてください。 このオプションは、C コンパイラが .so ファイルに対してシステムスタートアップライブラリをリンクしないようにします。 このオプションを付けないと、``multiple-definition'' (重複定義) エラーになってしまいます。 _init と _fini に関する議論を加えることを提案してくれたこと、 およびその作成を手伝ってくれたことに対して、 Jim Mischel と Tim Gentry に感謝します。

5.3. 共有ライブラリはスクリプト化できる

通常のライブラリ形式の代わりに、 特殊なスクリプト言語を使っているテキストファイルを共有ライブラリとして GNU ローダが認めることは、注目に値します。これは、 他のライブラリを間接的に結合させるのに役立ちます。例えば、 私の持つある一つのシステム上の /usr/lib/libc.so をリスティングしたものは次のようになります。
/* GNU ld スクリプト
   共有ライブラリを使うが、幾つかの関数は静的ライブラリ内にしか
   存在しない。そのため、二番目に試みる。 */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )

これに関するより詳しい情報は、ld リンカスクリプト (ld コマンド言語) についての texinfo ドキュメントを参照してください。 一般的な情報は、info:ld#Options と info:ld#Commands にあり、よく使うコマンドは info:ld#Option Commands で説明されています。

5.4. GNU libtool

多くのシステムに移植されるアプリケーションを作成しているならば、 ライブラリを構築しインストールするのに、 GNU libtool を使用することを考慮したほうがよいかもしれません。 GNU libtool は、汎用的なライブラリサポートスクリプトです。 Libtool は、共有ライブラリ使用の複雑さを一貫性のあるポータブルな インターフェースで隠します。Libtool は、 オブジェクト作成、ライブラリのリンク (静的および共有) 、 実行可能ファイルのリンク、実行可能ファイルのデバッグ、 ライブラリのインストール、実行可能ファイルのインストール、 についてポータブルなインターフェースを提供します。 また、プログラムを動的にロードするためのポータビリティラッパー である libltdl も含んでいます。より詳細な情報は、 http://www.gnu.org/software/libtool/manual.html を参照してください。

5.5. 極端に小さな実行可能ファイル

「本当に小さな Linux 用 ELF 実行可能ファイル作成に関する慌ただしいチュートリアル」 という文書が、よい参考となるでしょう。 これは、本当に小さな実行可能プログラムを作成する方法について論じています。 率直に言えば、一般的な環境では、これらのトリックのほとんどは使うべきではありませんが、 それらは、ELF が実際にどのように機能するかを示しているという点において、 極めて有益です。