Manpages

名 前

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 タ グ に 書 か れ て い る デ ィ レ ク ト リ リ ス ト を 検 索 す る 。

o

プ ロ グ ラ ム の 開 始 時 に 環 境 変 数 LD_LIBRARY_PATH に コ ロ ン 区 切 り の デ ィ レ ク ト リ の リ ス ト が 定 義 さ れ て い れ ば 、 こ の 環 境 変 数 に 定 義 さ れ た デ ィ レ ク ト リ が 検 索 さ れ る (セ キ ュ リ テ ィ 上 の 理 由 で 、 こ の 変 数 は set−UID や set−GID さ れ た プ ロ グ ラ ム の 場 合 は 無 視 さ れ る )。
o

(ELF の み ) 呼 び 出 し 元 プ ロ グ ラ ム の 実 行 フ ァ イ ル に DT_RUNPATH タ グ が 含 ま れ て い る 場 合 、 そ の タ グ に 書 か れ て い る デ ィ レ ク ト リ リ ス ト を 検 索 す る 。

o

キ ャ ッ シ ュ フ ァ イ ル /etc/ld.so.cache の 中 に filename の エ ン ト リ ー が 入 っ て い る か を チ ェ ッ ク す る (/etc/ld.so.cacheldconfig(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_DEFAULTRTLD_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 /* feature_test_macros(7) 参 照 */
#include <dlfcn.h>

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 symbol whose definition
overlaps addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */ }
Dl_info;

addr に マ ッ チ す る シ ン ボ ル が 見 つ か ら な か っ た 場 合 、 dli_snamedli_saddr は NULL に セ ッ ト さ れ る 。

dladdr() は 、 エ ラ ー 時 に は 0 を 返 し 、 成 功 し た 場 合 は 0 以 外 を 返 す 。 関 数 dlvsym() は dlsym() と 同 じ 動 作 を す る が 、 バ ー ジ ョ ン の 文 字 列 を 渡 す 引 き 数 が 追 加 さ れ て い る 点 が 異 な る (dlvsym() は バ ー ジ ョ ン 2.1 以 降 の glibc で 提 供 さ れ て い る )。

準 拠

POSIX.1−2003 に は dlclose(), dlerror(), dlopen(), dlsym(). の 記 載 が あ る 。

注 意

シ ン ボ ル RTLD_DEFAULTRTLD_NEXT<dlfcn.h> で 定 義 さ れ て お り 、 <dlfcn.h> の イ ン ク ル ー ド 前 に _GNU_SOURCE が 定 義 さ れ て い る 場 合 の み 有 効 と な る 。

glibc 2.2.3 以 降 で は 、 atexit(3) を 使 っ て 、 ラ イ ブ ラ リ が ア ン ロ ー ド さ れ る 際 に 自 動 的 に 呼 び 出 さ れ る 終 了 ハ ン ド ラ ー (exit handler) を 登 録 す る こ と が で き る 。 歴 史
dlopen イ ン タ ー フ ェ ー ス の 標 準 は SunOS を も と に し て い る 。 SunOS に は dladdr() も あ っ た が 、 dlvsym() は な か っ た 。

バ グ

時 と し て 、 dladdr() に 渡 し た 関 数 ポ イ ン タ ー は 驚 く よ う な 値 に な る こ と が あ る 。 い く つ か の ア ー キ テ ク チ ャ ー (特 に i386 と x86_64) で は 、 引 き 数 と し て 使 用 し た 関 数 が 動 的 リ ン ク ラ イ ブ ラ リ で 定 義 さ れ る も の で あ っ た と し て も 、 dli_fnamedli_fbasedladdr() を 呼 び 出 し た オ ブ ジ ェ ク ト を 参 照 し た 状 態 で 終 わ っ て い る こ と が あ る 。 問 題 は 、 関 数 ポ イ ン タ ー の 解 決 は 今 な お コ ン パ イ ル 時 に 行 わ れ る が 、 そ の ポ イ ン タ ー は 元 の オ ブ ジ ェ ク ト の plt (Procedure Linkage Table) セ ク シ ョ ン を 指 し て い る だ け だ と い う 点 に あ る (オ ブ ジ ェ ク ト 自 体 は 、 ダ イ ナ ミ ッ ク リ ン カ ー に よ っ て シ ン ボ ル の 解 決 が 行 わ れ た 後 に 、 関 数 の 呼 び 出 し を 行 う )。 こ れ に 対 処 す る 方 法 と し て は 、 コ ー ド を position−independent で コ ン パ イ ル す る と い う 方 法 が あ る 。 そ う す る と 、 コ ン パ イ ラ は コ ン パ イ ル 時 に ポ イ ン タ ー を 用 意 す る こ と が で き ず 、 今 日 の gcc(1) で は 、 実 行 時 に dladdr() に 関 数 ポ イ ン タ ー を 渡 す 前 に 、 got (Global Offset Table) か ら 最 終 的 な シ ン ボ ル の ア ド レ ス を ロ ー ド す る だ け の コ ー ド が 生 成 さ れ る 。

math ラ イ ブ ラ リ を ロ ー ド し 、 2.0 の 余 弦 を 表 示 す る

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

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 */

cosine = (double (*)(double)) dlsym(handle, "cos");

/* ISO の C 標 準 に よ れ ば 、 上 の よ う な 、 関 数 ポ イ ン タ ー と ’void *’ 間 の キ ャ ス ト を 行 っ た 場 合 に 得 ら れ る 結 果 は 不 定 で あ る 。
POSIX.1−2003 と POSIX.1−2008 で は 、 こ の 状 況 は 認 め ら れ て お り 、 以 下 の よ う な ワ ー ク ア ラ ウ ン ド が 提 案 さ れ て い る 。

*(void **) (&cosine) = dlsym(handle, "cos"); こ の
(ぶ か っ こ う な ) キ ャ ス ト は ISO の C 標 準 に 従 っ て お り 、 コ ン パ イ ラ の 警 告 を 避 け る こ と が で き る 。

POSIX.1−2008 の 2013 Technical Corrigendum (別 名 POSIX.1−2013) で は 、
POSIX に 準 拠 す る 実 装 で は ’void *’ か ら 関 数 ポ イ ン タ ー へ の キ ャ ス ト を サ ポ ー ト す る こ と が 要 求 さ れ る よ う に な り 、 状 況 が 改 善 さ れ た 。 に も か か わ ら ず 、
(’−pedantic’ オ プ シ ョ ン を 指 定 し た gcc な ど の
) い く つ か の コ ン パ イ ラ は 、 こ の プ ロ グ ラ ム で 使 用 さ れ て い る キ ャ ス ト に つ い て 文 句 を 言 う の だ 。

error = dlerror();
if (error != 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), 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/ に 書 か れ て い る 。