この章は今のところまだ短いです。私が ELF HOWTO の内容を消化するに連れ、 だんだん拡張されていくでしょう。
前の章全部を一気に読んだ人はもう聞き飽きたかもしれませんが、 Linux は 共有ライブラリを利用しています。「名前を検索して置き換える」という動作 が、リンク時から実行時に先送りされるようになったのです。
リンクエラーが起こったら送ってください!解決はできないかもしれませんが、 ここにまとめたいと思います...
can't load library: /lib/libxxx.so, Incompatible version
(a.out のみ)これは xxx ライブラリの major バージョンがあっていないか らです。ただシンボリックリンクを違うバージョンのライブラリに張っただけ ではだめですよ(そんなことをして segfault くらいで済んだら幸運というも のです)。新しいバージョンを入手してください。 ELF の場合、同じような 状況では以下のようなメッセージとなります。
ftp: can't load library 'libreadline.so.2'
warning using incompatible library version xxx
(a.out のみ)このメッセージを吐いたプログラムをコンパイルした人よりも minor バージョンが古いライブラリを使っている場合に出ます。多分プログ ラムはちゃんと動くと思います。でもアップグレードした方が良いでしょうね。
ダイナミックローダが参照する環境変数は多岐に渡っています。これらのほと
んどは ldd
だけが使うものなので、 ldd
に対応するスイッチをつ
けて実行する方が便利かもしれません。
LD_BIND_NOW
通常ライブラリ中の関数は、呼び出されるまでアク
セスされません。このフラグを設定しておくと、ライブラリがロードされたと
きに全ての関数が確認されます( したがって時間がかかります)。このオプショ
ンはプログラムをテストするときに、全てがちゃんとリンクされているかを確
認するときに役に立ちます。
LD_PRELOAD
を使うと関数定義を「上書き」するファイルを指定
できます。例えばメモリ割り当て関数を実装して、これを `malloc' と置き換
えたい場合には、その実装を malloc.o
にコンパイルして以下のように
します。
$ LD_PRELOAD=malloc.o; export LD_PRELOAD
$ some_test_program
LD_ELF_PRELOAD
と LD_AOUT_PRELOAD
も同じような機能を持ちます
が、それぞれのバイナリ形式に対してのみ有効になります。
LD_
something_PRELOAD
と LD_PRELOAD
が同時に定義さ
れている場合は、範囲の狭い指定の方が有効になります。
LD_LIBRARY_PATH
はコロンで区切られたリストで、共有ライブラ
リを検索するディレクトリを指定します。この指定は実行時のみに用いられ、
ld
には影響しません。また setuid や setgid されたプログラムには無
効です。これにも LD_ELF_LIBRARY_PATH
と LD_AOUT_LIBRARY_PATH
があり、バイナリ形式によって異なる検索リストを指定できます。通常は
LD_LIBRARY_PATH
は必要ないでしょう。ディレクトリを
/etc/ld.so.conf
に加えて ldconfig を実行しなおす方をお勧めし
ます。
LD_NOWARN
は a.out のみに適用されます。設定されていると
(つまり LD_NOWARN=true; export LD_NOWARN
)、ローダは致命的でない
警告メッセージ(minor バージョンがあっていないなど)を出力しなくなりま
す。
LD_WARN
は ELF にのみ適用されます。設定されていると通常は
致命的エラーである ``Can't find library'' をワーニングに変えます。通常
はあまり利用されることはないでしょうが、 ldd には重要な設定です。
LD_TRACE_LOADER_OBJECTS
は ELF にのみ適用されます。指定す
ると、それぞれの実行プログラムは、自分が ldd
の下で実行されている
ものと考えるようになります。
$ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx
libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
libc.so.5 => /lib/libc.so.5.2.18
Solaris 2.x でのダイナミックロード機能と非常に似ています(といっても
Solaris ユーザにしかわかりませんね)。具体的な内容は H. J. Lu の ELF
programming document および dlopen(3)
の man ページで詳述されてい
ます。後者は ld.so のパッケージに入っています。以下にもちょっとした例
を示します。 -ldl
をつけてリンクしてください。
#include <dlfcn.h>
#include <stdio.h>
main()
{
void *libc;
void (*printf_call)();
if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY))
{
printf_call=dlsym(libc,"printf");
(*printf_call)("hello, world\n");
}
}