dlopenのヘルプ・マニュアル
日本語 英語
dlopen --help
man dlopen
DLOPEN(3) Linux Programmer’s Manual DLOPEN(3)
名前
dlclose, dlerror, dlopen, dlsym - 動的リンクを行うローダへのプログラミ
ングインターフェース
書式
#include
void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
-ldl でリンクする。
説明
dlopen(), dlsym(), dlclose(), dlerror() の 4つの関数は、 動 的 リ ン ク
(dynamic linking) を行うローダへのインタフェースを実装したものである。
dlerror()
関 数 dlerror() は 、 前 回 dlerror() が呼び出された後に、 dlopen(),
dlsym(), dlclose() のいずれかで最後に発生したエラーについての説明メッセ
ー ジを返す。初期化後または前回呼び出された後で、エラーが発生していなけ
れば NULL を返す。
dlopen()
関数 dlopen() は、NULL 終端された文字列 filename で指定されたファイル名
の動的ライブラリ (dynamic library) をロードし、その動的ライブラリへの内
部「ハンドル」を返す。 filename が NULL の場合、メイン・プログラムへ の
ハ ンドルが返される。 filename がスラッシュ ("/") を含む場合、(相対か絶
対かの)パス名として解釈される。それ以外の場合、動的リンカは以下の手順で
ライブラリを検索する (詳細は ld.so(8) を参照):
o (ELF のみ) 呼び出し元プログラムの実行ファイルに DT_RPATH タグが含ま
れており、 DT_RUNPATH タグが含まれていない場合、DT_RPATH タグに書か
れているディレクトリ・リストを検索する。
o プログラムの開始時に環境変数 LD_LIBRARY_PATH にコロン区切りのディレ
クトリのリストが定義されていれば、この環境変数に定義されたディレ ク
ト リ が 検 索される (セキュリティ上の理由で、この変数は set-UID や
set-GID されたプログラムの場合は無視される)。
o (ELF のみ) 呼び出し元プログラムの実行ファイルに DT_RUNPATH タグが含
ま れている場合、そのタグに書かれているディレクトリ・リストを検索す
る。
o キャッシュファイル /etc/ld.so.cache の中に filename のエントリが 入
っ ているかをチェックする (/etc/ld.so.cache は ldconfig(8) によって
管理されている)。
o ディレクトリ /lib と /usr/lib をこの順番で検索する。
そのライブラリが他の共有ライブラリに依存している場合は、依存している ラ
イ ブラリも動的リンカが同じ検索ルールに基づいて自動的にロードする (それ
らのライブラリにさらに依存関係がある場合などはこの処理は再帰的に行わ れ
る)。
flag には以下の 2 つの値のいずれかを含めなければならない:
RTLD_LAZY
lazy binding (手抜きなシンボルの結び付け) が行う。シンボルの解決
はそのシンボルを参照するコードが実行されるときにのみ行われる。シ
ンボルが一度も参照されなかった場合には、そのシンボルは解決されな
いままとなる。 (lazy binding は関数参照についてのみ実施さ れ る;
変数への参照は常にライブラリがロードされた時点で直ちに解決される
。)
RTLD_NOW
この値が指定されるか、環境変数 LD_BIND_NOW に空でない文字列が 設
定 さ れた場合、ライブラリ中の未定義のシンボルを全て解決してから
dlopen() は復帰する。解決できなかったときにはエラーが返される。
以下の値のうち 0 個以上を論理和 (OR) の形で flag に追加することも で き
る:
RTLD_GLOBAL
このライブラリで定義されているシンボルが、これより後でロードされ
るライブラリのシンボル解決で利用できるようになる。
RTLD_LOCAL
このフラグは RTLD_GLOBAL の反対の意味であり、どちらのフラグも 指
定されなかった場合はこちらがデフォルトとなる。このライブラリで定
義されているシンボルは、これより後でロードされるライブラリでのシ
ンボル参照で利用できない。
RTLD_NODELETE (glibc 2.2 以降)
dlclose() 中にそのライブラリをアンロードしない。そのため、同じラ
イブラリをこれ以降に dlopen() で再度ロードした場合に、ライブラリ
内の静的変数は再初期化されない。このフラグは POSIX.1-2001 では規
定されていない。
RTLD_NOLOAD (glibc 2.2 以降)
そのライブラリをロードしない。このフラグはそのライブラリがすでに
組 み込まれているかを検査するのに利用できる (dlopen() は、ライブ
ラリが組み込まれていなければ NULL を返し、すでに組み込まれていれ
ば そのライブラリのハンドルを返す)。また、すでにロードされている
ライブラリのフラグを昇格させるのにも利用できる。例えば、過 去 に
RTLD_LOCAL でロードしたライブラリを RTLD_NOLOAD | RTLD_GLOBAL で
再オープンすることができる。このフラグは POSIX.1-2001 では規定さ
れていない。
RTLD_DEEPBIND (glibc 2.3.4 以降)
このライブラリ内のシンボルの参照領域をグローバル領域よりも前に配
置する。つまり、内蔵型のライブラリでは、すでにロードされたライブ
ラリに含まれる同じ名前のグローバルなシンボルよりも自ライブラリ内
のシンボルが優先して使われる。このフラグは POSIX.1-2001 では規定
されていない。
filename が NULL ポインタである場合は、返されるハンドルはメイン・プログ
ラムのものになる。このハンドルが dlsym() に渡されると、シンボルの検索は
、 メイン・プログラム内、プログラムの起動時にロードされる全ての共有ライ
ブラリ、 dlopen() によって RTLD_GLOBAL フラグ付きでロードされた全ての共
有ライブラリ、の順序で行われる。
オ ープンされたライブラリ中での外部参照は、そのライブラリの依存リストに
あるライブラリか、 RTLD_GLOBAL フラグ付きで既にオープンされているライブ
ラ リ を 使 っ て 解 決 さ れ る 。 実 行 ファイルが "-rdynamic" フラグ
("--export-dynamic" も同義) 付きでリンクされている場合は、実行ファイ ル
中 のグローバルシンボルも、動的にロードされるライブラリ内の参照解決に用
いられる。
同じライブラリが dlopen() によって再度ロードされた場合には、同じファ イ
ル ハンドルが返される。 dl ライブラリはライブラリハンドルのリンク数を管
理している。したがって動的ライブラリは dlclose() が dlopen() と同じ回数
だけ呼び出されない限りアンロードされない。 _init() ルーチンは一度だけ呼
び出される (_init() が存在する場合のみ)。 RTLD_NOW が 指 定 さ れ て
dlopen() が呼び出された場合、 RTLD_LAZY で以前にロードされたライブラリ
のシンボル解決が実行されることがある。
dlopen() は、何らかの理由で失敗すると NULL を返す。
dlsym()
関数 dlsym() は、 dlopen() が返した動的ライブラリの「ハンド ル 」 と 、
NULL 終端されたシンボル名の文字列を引き数に取り、そのシンボルがロードさ
れたメモリのアドレスを返す。シンボルが、指定されたライブラリと、指定 さ
れ たライブラリがロードされる際に dlopen() が自動的にロードしてライブラ
リのいずれにも見つからない場合には、 dlsym() は NULL を返す (dlsym() に
よ る検索は、これらのライブラリの依存関係のツリーを先頭から辿って行われ
る)。実際にはシンボルの値自体が NULL になることもある ( そ の た め 、
dlsym() の返り値が NULL であったとしても必ずしもエラーという訳ではない)
。エラーかどうかを確認する正しい方法は以下の通りである: dlerror() を 呼
び出して以前のエラー状態をクリアしてから、 dlsym() を呼び出す。その後で
もう一度 dlerror() を呼び出して、 dlerror() の返り値を変数に保存し、 保
存した値が NULL であるか判定する。
RTLD_DEFAULT と RTLD_NEXT と い う二つの特別な擬似ハンドルがある。
RTLD_DEFAULT は、デフォルトのライブラリ検索順序にしたがって、検索対象の
シンボルが最初に現れるところを探す。 RTLD_NEXT は、ライブラリ検索順序の
中で現在のライブラリ以降で最初に関数が現れるところを探す。この機能を 使
うことで、別の共有ライブラリの関数へのラッパーを提供することができる。
dlclose()
関 数 dlclose() は動的ライブラリのハンドル handle の参照カウントを 1 減
らす。参照カウントが 0 になり、ロードされている他のライブラリからそのラ
イ ブラリ内のシンボルが使われていなければ、その動的ライブラリをアンロー
ドする。
関数 dlclose() は、成功した場合は 0 を返し、エラーの場合 0 以外を返す。
廃止されたシンボル _init() と _fini()
リ ンカは _init と _fini を特別なシンボルと解釈する。ある動的ライブラリ
で _init() という名前のルーチンがエクスポートされていれば、そのコードは
、 ライブラリのロード後、かつ dlopen() が復帰する前に実行される。その動
的ライブラリで _fini() という名前のルーチンがエクスポートされていれば、
ラ イブラリがアンロードされる直前にそのルーチンが呼び出される。システム
の起動ファイルに対するリンクを避ける必要がある場合、 gcc(1) のコマン ド
ラインに -nostartfiles オプションを指定すればよい。
こ のルーチンや、gcc のオプション -nostartfiles や -nostdlib は使用しな
いことを推奨する。これらを使うと、望ましくない動作をすることがある。 な
ぜなら、(特別な措置が行われない限り) これらの constructor/destructor ル
ーチンは実行されないからである。
代 わ り に 、 ラ イ ブ ラ リ は __attribute__((constructor)) や
__attribute__((destructor)) の関数属性を使って必要なルーチンをエクスポ
ートするのがよい。これらについては gcc の info ページを参照 の こ と 。
constructor ルーチンは dlopen() が復帰する前に実行され、 destructor ル
ーチンは dlclose() が復帰する前に実行される。
GNU での拡張: dladdr() と dlvsym()
glibc では POSIX には記載されていない関数が 2つ追加されている。プロトタ
イプは以下の通りである。
#define _GNU_SOURCE
#include
int dladdr(void *addr, Dl_info *info);
void *dlvsym(void *handle, char *symbol, char *version);
関 数 dladdr() は、関数のポインタを引き数にとり、関数の名前と関数が定義
されているファイルの解決を試みる。情報は Dl_info 構造体に格納される。
typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of nearest symbol with address
lower than addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;
addr にマッチするシンボルが見つからな か っ た 場 合 、 dli_sname と
dli_saddr は NULL にセットされる。
dladdr() は、エラー時には 0 を返し、成功した場合は 0 以外を返す。
関数 dlvsym() は dlsym() と同じ動作をするが、バージョンの文字列を渡す引
き数が追加されている点が異なる (dlvsym() はバージョン 2.1 以降の glibc
で提供されている)。
準拠
POSIX.1-2003 には dlclose(), dlerror(), dlopen(), dlsym(). の記載があ
る。
注意
シンボル RTLD_DEFAULT と RTLD_NEXT は で定義さ れ て お り 、
のインクルード前に _GNU_SOURCE が定義されている場合のみ有効と
なる。
glibc 2.2.3 以降では、 atexit(3) を使って、ライブラリがアンロードされる
際 に自動的に呼び出される終了ハンドラ (exit handler) を登録することがで
きる。
歴史
dlopen インターフェースの標準は SunOS をもとにしている。 SunOS に は
dladdr() もあったが、 dlvsym() はなかった。
バグ
時 として、 dladdr() に渡した関数ポインタは驚くような値になることがある
。いくつかのアーキテクチャ (特に i386 と x86_64) では、引き数として使用
し た 関 数 が 動 的 リンクライブラリで定義されるものであったとしても、
dli_fname と dli_fbase が dladdr() を呼び出したオブジェクトを参照した状
態で終わっていることがある。
問 題は、関数ポインタの解決は今なおコンパイル時に行われるが、そのポイン
タは元のオブジェクトの plt (Procedure Linkage Table) セクションを指して
い るだけだという点にある (オブジェクト自体は、ダイナミックリンカによっ
てシンボルの解決が行われた後に、関数の呼び出しを行う)。これに対処する方
法 としては、コードを position-independent でコンパイルするという方法が
ある。そうすると、コンパイラはコンパイル時にポインタを用意することが で
き ず、今日の gcc(1) では、実行時に dladdr() に関数ポインタを渡す前に、
got (Global Offset Table) から最終的なシンボルのアドレスをロードする だ
けのコードが生成される。
例
math ライブラリをロードし、2.0 の余弦を表示する
#include
#include
#include
int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%f\n", (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
このプログラムを "foo.c" に書いたとすると、以下のコマンドでプログラムを
ビルドできる。
gcc -rdynamic -o foo foo.c -ldl
_init() と _fini() をエクスポートするライブラリの場合は以下のようにして
コンパイルする必要がある。例として bar.c をコンパイルする場合:
gcc -shared -nostartfiles -o bar bar.c
関連項目
ld(1), ldd(1), dl_iterate_phdr(3), feature_test_macros(7), rtld-
audit(7), ld.so(8), ldconfig(8), ld.so info pages, gcc info pages, ld
info pages
Linux 2008-12-06 DLOPEN(3)
DLOPEN(3) Linux Programmer’s Manual DLOPEN(3)
NAME
dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym - programming interface
to dynamic linking loader
SYNOPSIS
#include
void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
Link with -ldl.
DESCRIPTION
The four functions dlopen(), dlsym(), dlclose(), dlerror() implement
the interface to the dynamic linking loader.
dlerror()
The function dlerror() returns a human readable string describing the
most recent error that occurred from dlopen(), dlsym() or dlclose()
since the last call to dlerror(). It returns NULL if no errors have
occurred since initialization or since it was last called.
dlopen()
The function dlopen() loads the dynamic library file named by the null-
terminated string filename and returns an opaque "handle" for the
dynamic library. If filename is NULL, then the returned handle is for
the main program. If filename contains a slash ("/"), then it is
interpreted as a (relative or absolute) pathname. Otherwise, the
dynamic linker searches for the library as follows (see ld.so(8) for
further details):
o (ELF only) If the executable file for the calling program contains
a DT_RPATH tag, and does not contain a DT_RUNPATH tag, then the
directories listed in the DT_RPATH tag are searched.
o If, at the time that the program was started, the environment vari-
able LD_LIBRARY_PATH was defined to contain a colon-separated list
of directories, then these are searched. (As a security measure
this variable is ignored for set-user-ID and set-group-ID pro-
grams.)
o (ELF only) If the executable file for the calling program contains
a DT_RUNPATH tag, then the directories listed in that tag are
searched.
o The cache file /etc/ld.so.cache (maintained by ldconfig(8)) is
checked to see whether it contains an entry for filename.
o The directories /lib and /usr/lib are searched (in that order).
If the library has dependencies on other shared libraries, then these
are also automatically loaded by the dynamic linker using the same
rules. (This process may occur recursively, if those libraries in turn
have dependencies, and so on.)
One of the following two values must be included in flag:
RTLD_LAZY
Perform lazy binding. Only resolve symbols as the code that
references them is executed. If the symbol is never referenced,
then it is never resolved. (Lazy binding is only performed for
function references; references to variables are always immedi-
ately bound when the library is loaded.)
RTLD_NOW
If this value is specified, or the environment variable
LD_BIND_NOW is set to a non-empty string, all undefined symbols
in the library are resolved before dlopen() returns. If this
cannot be done, an error is returned.
Zero of more of the following values may also be ORed in flag:
RTLD_GLOBAL
The symbols defined by this library will be made available for
symbol resolution of subsequently loaded libraries.
RTLD_LOCAL
This is the converse of RTLD_GLOBAL, and the default if neither
flag is specified. Symbols defined in this library are not made
available to resolve references in subsequently loaded
libraries.
RTLD_NODELETE (since glibc 2.2)
Do not unload the library during dlclose(). Consequently, the
library’s static variables are not reinitialized if the library
is reloaded with dlopen() at a later time. This flag is not
specified in POSIX.1-2001.
RTLD_NOLOAD (since glibc 2.2)
Don’t load the library. This can be used to test if the library
is already resident (dlopen() returns NULL if it is not, or the
library’s handle if it is resident). This flag can also be used
to promote the flags on a library that is already loaded. For
example, a library that was previously loaded with RTLD_LOCAL
can be re-opened with RTLD_NOLOAD | RTLD_GLOBAL. This flag is
not specified in POSIX.1-2001.
RTLD_DEEPBIND (since glibc 2.3.4)
Place the lookup scope of the symbols in this library ahead of
the global scope. This means that a self-contained library will
use its own symbols in preference to global symbols with the
same name contained in libraries that have already been loaded.
This flag is not specified in POSIX.1-2001.
If filename is a NULL pointer, then the returned handle is for the main
program. When given to dlsym(), this handle causes a search for a sym-
bol in the main program, followed by all shared libraries loaded at
program startup, and then all shared libraries loaded by dlopen() with
the flag RTLD_GLOBAL.
External references in the library are resolved using the libraries in
that library’s dependency list and any other libraries previously
opened with the RTLD_GLOBAL flag. If the executable was linked with
the flag "-rdynamic" (or, synonymously, "--export-dynamic"), then the
global symbols in the executable will also be used to resolve refer-
ences in a dynamically loaded library.
If the same library is loaded again with dlopen(), the same file handle
is returned. The dl library maintains reference counts for library
handles, so a dynamic library is not deallocated until dlclose() has
been called on it as many times as dlopen() has succeeded on it. The
_init() routine, if present, is only called once. But a subsequent
call with RTLD_NOW may force symbol resolution for a library earlier
loaded with RTLD_LAZY.
If dlopen() fails for any reason, it returns NULL.
dlsym()
The function dlsym() takes a "handle" of a dynamic library returned by
dlopen() and the null-terminated symbol name, returning the address
where that symbol is loaded into memory. If the symbol is not found,
in the specified library or any of the libraries that were automati-
cally loaded by dlopen() when that library was loaded, dlsym() returns
NULL. (The search performed by dlsym() is breadth first through the
dependency tree of these libraries.) Since the value of the symbol
could actually be NULL (so that a NULL return from dlsym() need not
indicate an error), the correct way to test for an error is to call
dlerror() to clear any old error conditions, then call dlsym(), and
then call dlerror() again, saving its return value into a variable, and
check whether this saved value is not NULL.
There are two special pseudo-handles, RTLD_DEFAULT and RTLD_NEXT. The
former will find the first occurrence of the desired symbol using the
default library search order. The latter will find the next occurrence
of a function in the search order after the current library. This
allows one to provide a wrapper around a function in another shared
library.
dlclose()
The function dlclose() decrements the reference count on the dynamic
library handle handle. If the reference count drops to zero and no
other loaded libraries use symbols in it, then the dynamic library is
unloaded.
The function dlclose() returns 0 on success, and non-zero on error.
The obsolete symbols _init() and _fini()
The linker recognizes special symbols _init and _fini. If a dynamic
library exports a routine named _init(), then that code is executed
after the loading, before dlopen() returns. If the dynamic library
exports a routine named _fini(), then that routine is called just
before the library is unloaded. In case you need to avoid linking
against the system startup files, this can be done by using the gcc(1)
-nostartfiles command-line option.
Using these routines, or the gcc -nostartfiles or -nostdlib options, is
not recommended. Their use may result in undesired behavior, since the
constructor/destructor routines will not be executed (unless special
measures are taken).
Instead, libraries should export routines using the __attribute__((con-
structor)) and __attribute__((destructor)) function attributes. See
the gcc info pages for information on these. Constructor routines are
executed before dlopen() returns, and destructor routines are executed
before dlclose() returns.
Glibc extensions: dladdr() and dlvsym()
Glibc adds two functions not described by POSIX, with prototypes
#define _GNU_SOURCE
#include
int dladdr(void *addr, Dl_info *info);
void *dlvsym(void *handle, char *symbol, char *version);
The function dladdr() takes a function pointer and tries to resolve
name and file where it is located. Information is stored in the
Dl_info structure:
typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of nearest symbol with address
lower than addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;
If no symbol matching addr could be found, then dli_sname and dli_saddr
are set to NULL.
dladdr() returns 0 on error, and non-zero on success.
The function dlvsym(), provided by glibc since version 2.1, does the
same as dlsym() but takes a version string as an additional argument.
CONFORMING TO
POSIX.1-2001 describes dlclose(), dlerror(), dlopen(), and dlsym().
NOTES
The symbols RTLD_DEFAULT and RTLD_NEXT are defined by only
when _GNU_SOURCE was defined before including it.
Since glibc 2.2.3, atexit(3) can be used to register an exit handler
that is automatically called when a library is unloaded.
History
The dlopen interface standard comes from SunOS. That system also has
dladdr(), but not dlvsym().
BUGS
Sometimes, the function pointers you pass to dladdr() may surprise you.
On some architectures (notably i386 and x86_64), dli_fname and
dli_fbase may end up pointing back at the object from which you called
dladdr(), even if the function used as an argument should come from a
dynamically linked library.
The problem is that the function pointer will still be resolved at com-
pile time, but merely point to the plt (Procedure Linkage Table) sec-
tion of the original object (which dispatches the call after asking the
dynamic linker to resolve the symbol). To work around this, you can
try to compile the code to be position-independent: then, the compiler
cannot prepare the pointer at compile time anymore and today’s gcc(1)
will generate code that just loads the final symbol address from the
got (Global Offset Table) at run time before passing it to dladdr().
EXAMPLE
Load the math library, and print the cosine of 2.0:
#include
#include
#include
int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%f\n", (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
If this program were in a file named "foo.c", you would build the pro-
gram with the following command:
gcc -rdynamic -o foo foo.c -ldl
Libraries exporting _init() and _fini() will want to be compiled as
follows, using bar.c as the example name:
gcc -shared -nostartfiles -o bar bar.c
SEE ALSO
ld(1), ldd(1), dl_iterate_phdr(3), feature_test_macros(7), rtld-
audit(7), ld.so(8), ldconfig(8), ld.so info pages, gcc info pages, ld
info pages
COLOPHON
This page is part of release 3.22 of the Linux man-pages project. A
description of the project, and information about reporting bugs, can
be found at http://www.kernel.org/doc/man-pages/.
Linux 2008-12-06 DLOPEN(3)