DLOPEN(3)

名前
dlclose, dlerror, dlopen, dlsym - ダイナミックリンクを行うローダへのプログラミングインターフェース

書式
#include <dlfcn.h>

void *dlopen (const char *filename, int flag);
const char *dlerror(void);
void *dlsym(void *handle, char *symbol);
int dladdr(void *address, Dl_info *dlip);
int dlclose (void *handle);

特殊なシンボル: _init, _fini.

説明
dlopen は null 終端文字列 filename で指定された名前のファイルをダイナミックライブラリとしてロードし、 そのダイナミックライブラリへ の非透過 (opaque) な「ハンドル」を返す。 filename が絶対パス ("/" で始まるパス) でない場合には、ファイル は以下の場所から検索される。

    ユーザーの LD_LIBRARY 環境変数で指定された、コロン区切りのディ レクトリリスト。

    /etc/ld.so.cache 中にあるライブラリのリスト。

    /usr/lib、 次いで /lib。

filename が NULL ポインタである場合は、 返されるハンドルはメインプログラムのものになる。

オープンされたライブラリ中での外部参照は、 そのライブラリの依存リストにあるライブラリか、すでに RTLD_GLOBAL フラグと共にオープンされているライブラリを用いて解決される。 実行ファイルが "-rdynamic" フラグとともにリンクされている場合は、 実行ファイル中のグローバルシンボルも、 ダイナミックにロードされるライブラリへの参照解決に用いられる。

flag は以下のいずれかでなければならない: RTLD_LAZY はダイナミックライブラリのコードが実行される際に 未定義シンボルを順次解決していくことを示し、 RTLD_NOW は dlopen の処理の最後ですべての未定義シンボルを解決し、これができない場合には dlopen が失敗となることを示す。さらに RTLD_GLOBAL を flag に OR 演算させることもできる。この場合には、ライブラリで定義されている 外部シンボルが、引き続いてロードされる他のライブラリでも有効になる。

ライブラリが _init という名前のルーチンをエクスポートしていれば、 dlopen が終了する前にそ のコードが実行される。同じライブラリが dlopen() によって二度ロードされた場合には、同じファイルハンドルが返される。 dl ライブラリはダイナミックファイルハンドルのリンク数を保持している。 したがってダイナミックライブラリは dlclose が dlopen と同じ回数だけ呼び出されなければアンロードされない。

dlopen は、何らかの理由で失敗すると NULL を返す。 dl ルーチン (dlopen, dlsym, dlclose) のいずれかで 最も近い過去に生じたエラーは、 dlerror() によって人間に可読な形で表示させることができる。 dlerror は初期化された時点、あるいは最後に呼び出された時点からエラーが起こって いなければ NULL を返す。 ( dlerror() を 2 回続けて呼び出すと、 2 度目のコールでは必ず NULL が返る。)

dlsym は dlopen によって返されたダイナミックライブラリの「ハンドル」と、 ヌル文字で終端された文字列のシンボル名を引き数に取り、 そのシンボルがロードされているアドレスを返す。 シンボルが見つからない場合には、 dlsym は NULL を返す。しかし dlsym のエラーを調べるには、 dlerror の結果を変数に保存し、 それが NULL でないかどうかをチェックするのが正しいやり方である。 シンボルの値が実際に NULL である場合もあり得るからである。また dlerror の結果を変数に保存しておくことも必要なことである。なぜならもう一度 dlerror を呼び出すと、返り値は NULL となってしまうからである。

dladdr は、 address で指定されたメモリ位置を所有している共有ライブラリに関する情報を返す。 dladdr は成功するとゼロを、失敗すると非ゼロの値を返す。

dlclose はダイナミックライブラリのハンドル handle の参照カウントを 1 減らす。参照カウントが 0 になり、他でロードされてい るライブラリによってシンボルが使われていなければ、そのダイナミックライ ブラリはアンロードされる。そのダイナミックライブラリによって _fini という名前のルーチンがエクスポートされている場合には、 ライブラリをアンロードする直前にそのルーチンが呼び出される。

例
math ライブラリをロードし、2.0 の余弦を表示する。
    #include <dlfcn.h>
    int main(int argc, char **argv) {
        void *handle = dlopen ("/lib/libm.so", RTLD_LAZY);
        double (*cosine)(double) = dlsym(handle, "cos");
        printf ("%f\n", (*cosine)(2.0));
        dlclose(handle);
    }

    このプログラムを "foo.c" に書いたとすると、以下のコマンドでプログラム をビルドすることができる。

        gcc -rdynamic -o foo foo.c -ldl

同じことをしているが、すべての段階でエラーチェックを行っている:
    #include <stdio.h>
    #include <dlfcn.h>
    int main(int argc, char **argv) {
        void *handle;
        double (*cosine)(double);
        char *error;
        handle = dlopen ("/lib/libm.so", RTLD_LAZY);
        if (!handle) {
            fputs (dlerror(), stderr);
            exit(1);
        }
        cosine = dlsym(handle, "cos");
        if ((error = dlerror()) != NULL)  {
            fputs(error, stderr);
            exit(1);
        }
        printf ("%f\n", (*cosine)(2.0));
        dlclose(handle);
    }

謝辞
dlopen インターフェースの標準は Solaris をもとにしている。 Linux の dlopen の実装は、当初 Eric Youngdale によってなされた。 このとき Mitch D'Souza, David Engel, Hongjiu Lu, Andreas Schwab らの 助力があった。 このマニュアルページは Adam Richter が書いた。

関連項目
ld(1), ld.so(8), ldconfig(8), ldd(1)