名 前
dlclose, dlerror, dlopen, dlsym − 動 的 リ ン ク を 行 う ロ ー ダ ー へ の プ ロ グ ラ ミ ン グ イ ン タ ー フ ェ ー ス
書 式
#include <dlfcn.h>
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() は 、 ヌ ル 終 端 さ れ た 文 字 列 filename で 指 定 さ れ た フ ァ イ ル 名 の 動 的 ラ イ ブ ラ リ (dynamic library) を ロ ー ド し 、 そ の 動 的 ラ イ ブ ラ リ へ の 内 部 「 ハ ン ド ル 」 を 返 す 。 filename が NULL の 場 合 、 メ イ ン プ ロ グ ラ ム へ の ハ ン ド ル が 返 さ れ る 。 filename が ス ラ ッ シ ュ ("/") を 含 む 場 合 、 (相 対 か 絶 対 か の )パ ス 名 と し て 解 釈 さ れ る 。 そ れ 以 外 の 場 合 、 動 的 リ ン カ ー は 以 下 の 手 順 で ラ イ ブ ラ リ を 検 索 す る (詳 細 は ld.so(8) を 参 照 ):
o |
(ELF の み ) 呼 び 出 し 元 プ ロ グ ラ ム の 実 行 フ ァ イ ル に DT_RPATH タ グ が 含 ま れ て お り 、 DT_RUNPATH タ グ が 含 ま れ て い な い 場 合 、 DT_RPATH タ グ に 書 か れ て い る デ ィ レ ク ト リ リ ス ト を 検 索 す る 。
プ ロ グ
ラ ム の 開 始 時
に 環 境 変 数
LD_LIBRARY_PATH に コ ロ ン
区 切 り の デ ィ
レ ク ト リ の リ
ス ト が 定 義 さ
れ て い れ ば 、
こ の 環 境 変 数
に 定 義 さ れ た
デ ィ レ ク ト リ
が 検 索 さ れ る
(セ キ ュ リ テ ィ
上 の 理 由 で 、
こ の 変 数 は set−UID
や set−GID さ れ た プ
ロ グ ラ ム の 場
合 は 無 視 さ れ
る )。 (ELF の み ) 呼 び 出 し 元 プ ロ グ ラ ム の 実 行 フ ァ イ ル に DT_RUNPATH タ グ が 含 ま れ て い る 場 合 、 そ の タ グ に 書 か れ て い る デ ィ レ ク ト リ リ ス ト を 検 索 す る 。
キ ャ ッ シ ュ フ ァ イ ル /etc/ld.so.cache の 中 に filename の エ ン ト リ ー が 入 っ て い る か を チ ェ ッ ク す る (/etc/ld.so.cache は ldconfig(8) に よ っ て 管 理 さ れ て い る )。 デ ィ レ ク ト リ /lib と /usr/lib を こ の 順 番 で 検 索 す る 。 そ の ラ イ ブ ラ リ が 他 の 共 有 ラ イ ブ ラ リ に 依 存 し て い る 場 合 は 、 依 存 し て い る ラ イ ブ ラ リ も 動 的 リ ン カ ー が 同 じ 検 索 ル ー ル に 基 づ い て 自 動 的 に ロ ー ド す る (そ れ ら の ラ イ ブ ラ リ に さ ら に 依 存 関 係 が あ る 場 合 な ど は こ の 処 理 は 再 帰 的 に 行 わ れ る )。 flag
に は 以 下 の 2 つ
の 値 の い ず れ
か を 含 め な け
れ ば な ら な い :
lazy binding (手 抜 き な シ ン ボ ル の 結 び 付 け ) が 行 う 。 シ ン ボ ル の 解 決 は そ の シ ン ボ ル を 参 照 す る コ ー ド が 実 行 さ れ る と き に の み 行 わ れ る 。 シ ン ボ ル が 一 度 も 参 照 さ れ な か っ た 場 合 に は 、 そ の シ ン ボ ル は 解 決 さ れ な い ま ま と な る 。 (lazy binding は 関 数 参 照 に つ い て の み 実 施 さ れ る ; 変 数 へ の 参 照 は 常 に ラ イ ブ ラ リ が ロ ー ド さ れ た 時 点 で 直 ち に 解 決 さ れ る 。 ) RTLD_NOW こ
の 値 が 指 定 さ
れ る か 、 環 境
変 数 LD_BIND_NOW に 空
で な い 文 字 列
が 設 定 さ れ た
場 合 、 ラ イ ブ
ラ リ 中 の 未 定
義 の シ ン ボ ル
を 全 て 解 決 し
て か ら dlopen() は 復
帰 す る 。 解 決
で き な か っ た
と き に は エ ラ
ー が 返 さ れ る
。 以 下 の 値 の
う ち 0 個 以 上 を
論 理 和 (OR) の 形 で
flag に 追 加 す る
こ と も で き る :
dlclose() 中 に そ の ラ イ ブ ラ リ を ア ン ロ ー ド し な い 。 そ の た め 、 同 じ ラ イ ブ ラ リ を こ れ 以 降 に dlopen() で 再 度 ロ ー ド し た 場 合 に 、 ラ イ ブ ラ リ 内 の 静 的 変 数 は 再 初 期 化 さ れ な い 。 こ の フ ラ グ は POSIX.1−2001 で は 規 定 さ れ て い な い 。 RTLD_NOLOAD (glibc 2.2
以 降 ) そ の ラ イ
ブ ラ リ を ロ ー
ド し な い 。 こ
の フ ラ グ は そ
の ラ イ ブ ラ リ
が す で に 組 み
込 ま れ て い る
か を 検 査 す る
の に 利 用 で き
る (dlopen() は 、 ラ
イ ブ ラ リ が 組
み 込 ま れ て い
な け れ ば NULL を 返
し 、 す で に 組
み 込 ま れ て い
れ ば そ の ラ イ
ブ ラ リ の ハ ン
ド ル を 返 す )。
ま た 、 す で に
ロ ー ド さ れ て
い る ラ イ ブ ラ
リ の フ ラ グ を
昇 格 さ せ る の
に も 利 用 で き
る 。 例 え ば 、
過 去 に RTLD_LOCAL で
ロ ー ド し た ラ
イ ブ ラ リ を
RTLD_NOLOAD | RTLD_GLOBAL で 再
オ ー プ ン す る
こ と が で き る
。 こ の フ ラ グ
は 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()
#define
_GNU_SOURCE /* feature_test_macros(7) 参 照
*/ int dladdr(void *addr, Dl_info *info); void *dlvsym(void *handle, char *symbol, char *version); 関 数 dladdr() は 、 関 数 の ポ イ ン タ ー を 引 き 数 に と り 、 関 数 の 名 前 と 関 数 が 定 義 さ れ て い る フ ァ イ ル の 解 決 を 試 み る 。 情 報 は Dl_info 構 造 体 に 格 納 さ れ る 。 typedef struct
{ 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 は <dlfcn.h> で 定 義 さ れ て お り 、 <dlfcn.h> の イ ン ク ル ー ド 前 に _GNU_SOURCE が 定 義 さ れ て い る 場 合 の み 有 効 と な る 。 glibc 2.2.3
以 降 で は 、
atexit(3) を 使 っ て
、 ラ イ ブ ラ リ
が ア ン ロ ー ド
さ れ る 際 に 自
動 的 に 呼 び 出
さ れ る 終 了 ハ
ン ド ラ ー (exit handler) を
登 録 す る こ と
が で き る 。 歴
史 バ グ時 と し て 、 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
<stdio.h> int handle =
dlopen("libm.so", RTLD_LAZY); dlerror(); /* Clear any existing error */ cosine = (double (*)(double)) dlsym(handle, "cos"); /* ISO の
C 標 準 に よ れ ば
、 上 の よ う な
、 関 数 ポ イ ン
タ ー と ’void *’ 間
の キ ャ ス ト を
行 っ た 場 合 に
得 ら れ る 結 果
は 不 定 で あ る
。 *(void **)
(&cosine) = dlsym(handle, "cos"); こ
の POSIX.1−2008
の 2013 Technical Corrigendum (別 名
POSIX.1−2013) で は 、 error =
dlerror(); printf("%f\n",
(*cosine)(2.0)); gcc −rdynamic −o foo foo.c −ldl _init() と _fini() を エ ク ス ポ ー ト す る ラ イ ブ ラ リ の 場 合 は 以 下 の よ う に し て コ ン パ イ ル す る 必 要 が あ る 。 例 と し て bar.c を コ ン パ イ ル す る 場 合 : gcc −shared −nostartfiles −o bar bar.c 関 連 項 目ld(1), ldd(1), pldd(1), dl_iterate_phdr(3), rtld−audit(7), ld.so(8), ldconfig(8) ld.so info pages, gcc info pages, ld info pages こ の 文 書 に つ い てこ の man ペ ー ジ は Linux man−pages プ ロ ジ ェ ク ト の リ リ ー ス 3.79 の 一 部 で あ る 。 プ ロ ジ ェ ク ト の 説 明 と バ グ 報 告 に 関 す る 情 報 は http://www.kernel.org/doc/man−pages/ に 書 か れ て い る 。 |