DLOPEN(3) | FreeBSD Library Functions Manual | DLOPEN(3) |
名称
dlopen, fdlopen, dlsym, dlfunc, dlerror, dlclose — 動的 (ダイナミック) リンカのプログラムインタフェースライブラリ
Standard C Library (libc, -lc)書式
#include < dlfcn.h> void *
dlopen( const char *path, int mode);
void *
fdlopen( int fd, int mode);
void *
dlsym( void * restrict handle, const char * restrict symbol);
dlfunc_t
dlfunc( void * restrict handle, const char * restrict symbol);
char *
dlerror( void);
int
dlclose( void *handle);
解説
これらの関数は、動的リンカサービスに対する単純なプログラムのインタフェースを提供します。プログラムのアドレス空間に新しい共有オブジェクトを追加する操作、共有オブジェクトで定義されるシンボルのアドレス結合を取得する操作、および共有オブジェクトを使用する必要がなくなったときにそれを除去する操作が提供されています。dlopen() 関数は、 path 内の共有オブジェクトへのアクセスを提供し、 dlsym() と dlclose() の呼び出しにおいて、オブジェクトを後で参照するために使用可能な記述子を返します。 dlopen() を呼び出す前に path がアドレス空間になかった場合は、それは、アドレス空間に配置されます。この方法で、オブジェクトが初めてアドレス空間にロードされるとき、関数 _init() が存在すればそれは、動的リンカによって呼び出されます。先の dlopen() 呼び出しでアドレス空間に path が既に配置されている場合、2 度目は、追加されません。しかし、 path に対する dlopen() 操作の参照カウントは、保持されます。 path に供給された NULL ポインタは、プロセスの実行可能なメインの参照として解釈されます。 mode 引数は、ロードされたオブジェクトから外部関数への参照が、その参照先と結合する方法を制御します。これは、次の値のうちの 1 つが含まれていなくてはなりません。たぶん、後で述べる追加フラグとの OR をとった値になるでしょう。
- RTLD_LAZY
- それぞれの外部関数への参照は、関数が最初に呼び出されるときに解決されます。
- RTLD_NOW
- 全ての外部関数への参照は、 dlopen() によってただちに結合されます。
RTLD_LAZY は、効率的と理由で通常好まれます。しかしながら、 RTLD_NOW は、 dlopen() を呼び出している間に未定義シンボルを発見されるを保証するのに便利です。
次のフラグの 1 つは、OR をとって mode 引数にできます。
- RTLD_GLOBAL
- この共有オブジェクトのシンボルおよび必要とされるオブジェクトの有向非巡回グラフ (DAG) は、その他すべての共有オブジェクトの未定義参照を解決するために利用可能になります。
- RTLD_LOCAL
- この共有オブジェクトのシンボルおよび必要とされるオブジェクトの有向非巡回グラフ (DAG) は、同じ DAG の他のオブジェクトの未定義参照を解決するために利用可能になります。これは、デフォルトです。しかし、このフラグで明示的に指定できます。
- RTLD_TRACE
- 設定された時、この共有されるオブジェクトで必要とされるすべてのオブジェクトをロードした後に動的リンクをもたらします。そして、すべてのオブジェクトの絶対的パスネームを含んでいる要約を標準出力に印刷します。このフラグの dlopen() は、エラーの場合のみ呼び出し側に戻ります。
- RTLD_NODELETE
- dlclose() でロードされたオブジェクトのアンロードを防ぎます。同じ振る舞いは、静的なリンカ ld(1) の -z nodelete オプションで要求されます。
- RTLD_NOLOAD
- プロセスアドレス空間に既にロードされているなら、オブジェクトのための有効なハンドルを単に返します。そうでなければ、 NULL が返されます。オブジェクトを見つけるためのプロモーションに適用される、他のモードフラグが指定されるかもしれません。
dlopen() が失敗すると NULL ポインタを返し、 dlerror() で問いただしできるエラー状態を設定します。
fdlopen() 関数は、 dlopen() に似ていますが、アドレス空間にオブジェクトをロードするために必要とされるファイル操作のために使用される、ファイル記述子の引数 fd を取ります。ファイル記述子 fd は、実行の結果にかかわらず関数によってクローズさませんが、複写されたファイル記述子は、クローズされます。これは、 lockf(3) ロックが渡された記述子で保持されるなら、重要であるかもしれません。 fd 引数 -1 は、 dlopen() への name 引数のに対する NULL 値に似ている、プロセスのメインの実行形式を参照していると解釈されます。シンボリックリンクか、または名前が変更される競合を防ぐために、ロードされたオブジェクトで追加のチェックを行なう必要のあるコードによって fdlopen() 関数を使用することがでます。
dlsym() 関数は、 handle で識別される共有オブジェクトに存在する、ヌル文字で終了する文字列 symbol で記述されたシンボルのアドレス結合を返します。 dlopen() によってアドレス空間に追加されたオブジェクトによってエクスポート (export) されるシンボルは、 dlsym() 呼び出しを通してのみアクセスできます。そのようなシンボルは、オブジェクトがロードされる時に、すでにアドレス空間に存在しているシンボルの定義を入れ換えませんし、通常の動的リンク参照を満たすために利用可能でもありません。
dlsym() が特別な handle NULL で呼び出される場合、呼び出しがされている実行ファイルあるいは共有オブジェクトへの参照として解釈されます。したがって、共有オブジェクトは、自分自身のシンボルを参照できます。
dlsym() が特別な handle RTLD_DEFAULT で呼び出される場合、シンボルの検索は、オブジェクトがロードされる時に未定義のシンボルを解決するために使用されるアルゴリズムに従います。検索されるオブジェクトは、次のような順序となります。
- オブジェクトが ld(1) のオプションとして -Wsymbolic を使用してリンクされた場合、参照しているオブジェクト自身 (あるいは dlsym() への呼び出されるオブジェクト)となります。
- プログラムの起動時にロードされた全オブジェクト。
- RTLD_GLOBAL フラグを mode 引数で設定して呼び出した dlopen() 経由でロードされた全オブジェクト
- dlopen() 経由でロードされた全オブジェクト。これらのオブジェクトは、参照しているオブジェクトも含んだ、必要とされるオブジェクトの有向非巡回グラフ (DAG)。
dlsym() が特別な handle RTLD_NEXT で呼び出される場合、シンボルの検索は、 dlsym() 呼び出しを発行した後でロードされた共有オブジェクトに制限されます。したがって、メインプログラムから関数が呼び出された場合、すべての共有ライブラリが検索されます。共有ライブラリから呼び出された場合、その共有ライブラリに続く共有ライブラリすべてが検索されます。 RTLD_NEXT は、ライブラリ関数のラッパを実装するのに便利です。例えば、ラッパ関数 getpid() は、 dlsym(RTLD_NEXT, "getpid")
で“本物の” getpid() にアクセスできます。 (実際に、下記の dlfunc() インタフェースは、 getpid() がデータオブジェクトではなく、関数であるので、使用されるべきです。)
dlsym() が特別な handle RTLD_SELF で呼ばれる場合、シンボルの検索は、 dlsym() への呼び出しを発行する共有オブジェクトに制限されています。そして、それらの共有オブジェクトは、その後にロードされます。
シンボルが見つけられなかった場合、 dlsym() 関数は、NULL ポインタを返し、 dlerror() で問い合わせることができるエラー状態を設定します。
dlfunc() 関数は、 dlsym() の振る舞いのすべてを実装しますが、コンパイラ診断の要因とならない関数ポインタにキャストすることができるリターン (返り) タイプを持っています。 ( dlsym() 関数は、データポインタを返します。 C 規格では、データと関数ポインタタイプの間の変換は、未定義です。いくつかのコンパイラと lint(1) ユーティリティは、そのようなキャストについて警告します。) dlfunc() の正確なリターンタイプは、特定されません。アプリケーションは、それを適切な関数ポインタタイプにキャストしなければなりません。
dlerror() 関数は、 dlopen(), dladdr(), dlinfo(), dlsym(), dlfunc() または dlclose() 呼び出しの間に発生した最後のエラーを記述するヌル文字で終了する文字列を返します。このようなエラーが発生していない場合、 dlerror() は、 NULL ポインタを返します。 dlerror() を呼び出すたびに、エラー指示は、リセットされます。したがって、2番目の呼び出しが最初の呼び出しの直後にくるような dlerror() の呼び出しを2回行った場合、2番目の呼び出しは、必ず NULL ポインタが返ります。
dlclose() 関数は、 handle で参照される共有オブジェクトへの参照を削除します。参照カウントが 0 まで減らされると、そのオブジェクトは、アドレス空間から取り除かれ handle は、無効になります。この方法で共有オブジェクトが取り除かれる直前に、 _fini() 関数がこのオブジェクトで定義されている場合は、動的リンカは、オブジェクトのその関数を呼び出します。 dlclose() は、成功すると値 0 を返します。そうでない場合は、-1 を返し、 dlerror() で問い合わせできるエラー状態を設定します。
オブジェクトに固有の関数 _init() と _fini() は、引数なしに呼び出され、戻り値は、要求されません。
注
ELF 実行可能ファイルの場合、ファイル中で定義されているシンボルを dlsym() で見えるようにするには、 ld(1) に対して -export-dynamic オプションを使用してリンクする必要があります。以前の実装では、C 言語でコンパイルしたオブジェクトコードとのシンボルの互換性を得るために外部シンボルは、すべて下線を先頭につける必要がありました。これは、C 言語のコンパイラに (時代遅れですが) -aout オプションを使用した場合に当てはまります。
エラー
dlopen(), fdlopen(), dlsym() と dlfunc() 関数は、エラーが発生した場合には、NULL ポインタを返します。 dlclose() 関数は、成功すると 0 を返し、エラーが発生した場合は、-1 を返します。エラーが検出されるときは、いつも、メッセージの詳細な記述は、 dlerror() 呼び出しによって取り出すことができます。December 21, 2011 | FreeBSD |