ld.so, ld-linux.so* -
動的なリンカー/ローダー
動的リンカーは、動的にリンクされたプログラムやライブラリの実行によって
間接的に実行することができる
(ELF
の場合、動的リンカーにコマンドラインオプションを渡すことはできず、
プログラムの
.interp
セクションに入っている動的リンカーが実行される)。
また以下のように直接実行することもできる
/lib/ld-linux.so.* [OPTIONS] [PROGRAM [ARGUMENTS]]
プログラム
ld.so と
ld-linux.so*
はプログラムに必要な共有ライブラリを見つけてロードし、
プログラムの実行を準備してから起動させる。
Linux
のバイナリは、コンパイルの時に
ld(1) に対して
-static
オプションが指定されていない限り、動的リンク
(実行時リンク)
が必要となる。
プログラム
ld.so は a.out
バイナリを扱う。
これはずっと昔に使われていたフォーマットである。
ld-linux.so* (libc5 では
/lib/ld-linux.so.1, glibc2
では
/lib/ld-linux.so.2) は ELF
バイナリを扱う。
このフォーマットは多くの人が最近何年も使っている。
それ以外の点では両方とも同じように動作し、
同じサポートファイルとプログラム
ldd(1),
ldconfig(8),
/etc/ld.so.conf
を使用する。
ライブラリの依存関係を解決する際、動的リンカーは、最初に、依存関係の各文字列がスラッシュを含んでいるかをチェックする
(この状況になるのは、リンク時にスラッシュを含むライブラリのパス名が指定された場合である)。スラッシュが見つかった場合、その依存関係の文字列はパス名
(相対パス、絶対パスのどちらも可)
として解釈され、そのパス名を使ってそのライブラリはロードされる。
ライブラリの依存関係にスラッシュが含まれない場合、以下の順序で検索される。
- o
- (ELF のみ)
バイナリの動的セクション属性
DT_RPATH が存在し、 DT_RUNPATH
属性が存在しない場合は、
DT_RPATH
で指定されたディレクトリを使用する。
DT_RPATH
の使用は推奨されない。
- o
- 環境変数 LD_LIBRARY_PATH
を用いる。
ただし実行ファイルが
set-user-ID/set-group-ID
バイナリの場合、
これは無視される。
- o
- (ELF のみ)
バイナリの動的セクション属性
DT_RUNPATH が存在すれば、
DT_RUNPATH
で指定されたディレクトリを使用する。
- o
- キャッシュファイル
/etc/ld.so.cache
を探す。このファイルは、
(ld.so.conf
で追加指定されたものも含めた)
ライブラリ検索パスから見つかったライブラリファイルの情報を集めたものである。ただし、バイナリがリンカーオプション
-z nodeflib
でリンクされている場合は、デフォルトのライブラリパスにある
ライブラリはスキップされる。ハードウェア機能ディレクトリ
(下記参照)
にインストールされたライブラリは、他のライブラリよりも優先される。
- o
- デフォルトパスである
/lib、 次いで /usr/lib
を用いる。
バイナリがリンカーオプション
-z nodeflib
でリンクされている場合、このステップはスキップされる。
ld.so では rpath 指定 (DT_RPATH や
DT_RUNPATH)
中にいくつかの特定の文字列を使うことができる。
それらの文字列は以下のように置き換えられる。
-
$ORIGIN (${ORIGIN}
も同じ)
- プログラムや共有ライブラリが入っているディレクトリに展開される。
したがって、 somedir/app
に置かれたアプリケーションを
gcc -Wl,-rpath,'$ORIGIN/../lib'
でコンパイルすることで、
somedir
がディレクトリ階層のどこにあっても、
ld.so は somedir/lib
にある対応する共有ライブラリを見つけることができる。
この機能を使うと、
特別なディレクトリではなく任意のディレクトリにインストールしても「ややこしい設定なしで」独自の共有ライブラリを使えるアプリケーションを作成することができる。
-
$LIB (${LIB} も同じ)
- アーキテクチャーに応じて
lib か lib64
に展開される
(例えば、 x86-64 では lib64
に、 x86-32 では lib
に展開される)。
-
$PLATFORM (${PLATFORM}
も同じ)
- ホストシステムのプロセッサ種別に対応する文字列に展開される
(例えば "x86_64")。
いくつかのアーキテクチャーでは、
Linux
カーネルから動的リンカーにプラットフォームを表す文字列が提供されない。
この文字列の値は補助ベクトルの
AT_PLATFORM
値から取得される (
getauxval(3) 参照)。
- --list
- 全ての依存関係とその解決法をリストする。
- --verify
- プログラムが動的にリンクされているかと、
動的リンカーがそのプログラムを扱えるかを検証する。
- --inhibit-cache
- /etc/ld.so.cache
を使用しない。
- --library-path PATH
-
LD_LIBRARY_PATH
環境変数の設定ではなく、
指定した PATH
を使用する
(下記参照)。
- --inhibit-rpath LIST
- LIST
にあるオブジェクト名の
RPATH と RUNPATH
の情報を無視する。
ld.so が set-user-ID か set-group-ID
されている場合、
このオプションは無視される。
- --audit LIST
- LIST
で指定された名前のオブジェクトを監査者として使用する。
いくつかのライブラリは、(すべての
CPU
に存在するわけではない)ハードウェア固有
の命令を使ってコンパイルされている。そのようなライブラリは、
/usr/lib/sse2/
のような、必要なハードウェア機能
(hardware capability) を規
定する名前のディレクトリにインストールすべきである。
動的リンカーは、マシンのハードウェアに基づいてこれらのディレクトリを確認し、
指定されたライブラリに最も適したバージョンを選択する。
ハードウェア機能ディレクトリはつなげることができ、
複数の CPU
機能を組み合わることができる。
対応しているハードウェア機能名のリストは
CPU に依存する。
現在のところ、以下の名前が認識される。
- Alpha
- ev4, ev5, ev56, ev6, ev67
- MIPS
- loongson2e, loongson2f, octeon, octeon2
- PowerPC
- 4xxmac, altivec, arch_2_05, arch_2_06, booke, cellbe, dfp,
efpdouble, efpsingle, fpu, ic_snoop, mmu, notb, pa6t, power4, power5,
power5+, power6x, ppc32, ppc601, ppc64, smt, spe, ucache, vsx
- SPARC
- flush, muldiv, stbar, swap, ultra3, v9, v9v, v9v2
- s390
- dfp, eimm, esan3, etf3enh, g5, highgprs, hpage, ldisp, msa,
stfle, z900, z990, z9-109, z10, zarch
- x86 (32-bit のみ)
- acpi, apic, clflush, cmov, cx8, dts, fxsr, ht, i386, i486,
i586, i686, mca, mmx, mtrr, pat, pbe, pge, pn, pse36, sep, ss, sse, sse2,
tm
重要な環境変数には以下のものがある。
- LD_ASSUME_KERNEL
- (glibc 2.2.3 以降)
各共有ライブラリは動的リンカーに必要なカーネル
ABI
の最小バージョンを通知することができる
(必要なバージョンは
ELF の note section に格納され、
readelf -n で NT_GNU_ABI_TAG
のラベルが付いたセクションとして見ることができる)。
実行時に、
動的リンカーは実行中のカーネルの
ABI
バージョンを判定し、
カーネルの ABI
バージョンよりも大きな
ABI
の最小バージョンが指定された共有ライブラリのロードを行わない。
LD_ASSUME_KERNEL
を使うことで、
動的リンカーに、
異なるカーネル ABI
バージョンのシステムで実行されているかのように見せることができる。
例えば、
以下のコマンドラインを実行すると、
動的リンカーは myprog
が必要とする共有ライブラリをロードする際に
Linux 2.2.5
上で動作していると仮定する。
$ LD_ASSUME_KERNEL=2.2.5 ./myprog
必要なカーネル ABI
の最低バージョンが異なる複数の共有ライブラリが
(検索パス中の異なるディレクトリに)
あるシステムでは、
LD_ASSUME_KERNEL を使って
(ディレクトリ検索順序に基づき)
使用するライブラリのバージョンを選択することができる。
歴史的に見ると、
LD_ASSUME_KERNEL
の最も一般的な使い道は、
LinuxThreads と NPTL
の両方を提供しているシステムで、
古い LinuxThreads の POSIX
スレッド実装を手動で選択するためであった
(そのようなシステムでは、通常は
NPTL
がデフォルトであった)。
pthreads(7) を参照。
- LD_BIND_NOT
- (glibc 2.2 以降)
シンボルを解決した際、Global
Offset Table (GOT) と Procedure Linkage Table (PLT)
を更新しない。
- LD_BIND_NOW
- (libc5; glibc 2.1.1 以降)
空文字列でない場合、
動的リンカーはプログラムの開始時に全てのシンボルを解決する。
空文字列の場合、解決しなければならない関数呼び出しが
最初に参照された時点で解決する。
デバッガを使っているときに役立つ。
- LD_LIBRARY_PATH
- コロン区切りのディレクトリのリスト。実行時に
ELF
ライブラリを検索するディレクトリを指定する。
PATH
環境変数と同じように指定する。
set-user-ID/set-group-ID
されたプログラムでは無視される。
- LD_PRELOAD
- 追加でユーザーが指定する
ELF
共有ライブラリのリスト。指定されたライブラリは、すべてのライブラリより前にロードされる。リストの区切りはスペースとコロンである。他の共有ライブラリにある関数を選択的に置き換えるために用いることができる。指定されたライブラリは「説明」の節で述べたルールを基いて検索される。
set-user-ID/set-group-ID された ELF
バイナリでは、スラッシュを含んだパス名のライブラリは無視され、標準の検索ディレクトリのライブラリはそのライブラリファイルの
set-user-ID
許可ビットが有効になっている場合のみロードされる。
- LD_TRACE_LOADED_OBJECTS
- (ELF のみ)
空文字列でない場合、
プログラムを普通に実行するのではなく、
ldd(1)
を実行したときのように動的ライブラリの依存関係をリスト表示させる。
そして、それほど知られていない環境変数もある。
多くは廃れてしまったものか内部でのみ使用される環境変数である。
- LD_AOUT_LIBRARY_PATH
- (libc5) a.out
バイナリにのみ使われる環境変数で、
LD_LIBRARY_PATH
と同じ役割をする。
ld-linux.so.1
の古いバージョンでは
LD_ELF_LIBRARY_PATH
もサポートしていた。
- LD_AOUT_PRELOAD
- (libc5) a.out
バイナリにのみ使われる環境変数で、
LD_PRELOAD
と同じ役割をする。
ld-linux.so.1
の古いバージョンでは
LD_ELF_PRELOAD
もサポートしていた。
- LD_AUDIT
- (glibc 2.4 以降)
他のオブジェクトよりも前に、別のリンカー名前空間
(そのプロセスで行われる
通常のシンボル結合
(symbol bindigns)
には関与しない名前空間)
で
ロードされる、ユーザー指定の
ELF
共有オブジェクトのコロン区切りのリスト。
これらのライブラリを使って、動的リンカーの動作を監査することができる。
set-user-ID/set-group-ID
されたバイナリでは、
LD_AUDIT は無視される。
動的リンカーは、いわゆる監査チェックポイント
(auditing checkpoints)
において、監査 (audit)
ライブラリの適切な関数を呼び出すことで、
監査ライブラリへの通知を行う。監査チェックポイントの例としては、
新たなライブラリのロード、シンボルの解決、別の共有オブジェクト
からのシンボルの呼び出し、などがある。
詳細は rtld-audit(7)
を参照してほしい。
audit
インターフェースは、Solaris
で提供されているものと
大部分は互換性がある。Solaris
の audit
インターフェースについては、
Linker and Libraries Guide の Runtime Linker Auditing
Interface
の章に説明がある。
- LD_BIND_NOT
- (glibc 2.1.95 以降)
シンボルを解決した後、GOT
(global offset table) と PLT (procedure linkage table)
を更新しない。
- LD_DEBUG
- (glibc 2.1 以降)
動的リンカーの詳細なデバッグ情報を出力する。
all
に設定した場合、全ての動的リンカーが持つデバッグ情報を表示する。
help
に設定した場合、この環境変数で指定されるカテゴリーのヘルプ情報を表示する。
glibc 2.3.4 以降、 set-user-ID/set-group-ID
されたバイナリでは
LD_DEBUG
は無視される。
- LD_DEBUG_OUTPUT
- (glibc 2.1 以降) LD_DEBUG
の出力を書き込むファイル。
デフォルトは標準エラーである。
set-user-ID/set-group-ID
されたバイナリでは、
LD_DEBUG_OUTPUT
は無視される。
- LD_DYNAMIC_WEAK
- (glibc 2.1.19 以降)
上書きされる弱いシンボル
(昔の glibc
の挙動を逆にする)。
セキュリティ上の理由から、glibc
2.3.4 以降、 set-user-ID/set-group-ID
されたバイナリでは
LD_DYNAMIC_WEAK
は無視される。
- LD_HWCAP_MASK
- (glibc 2.1 以降)
ハードウェア機能のマスク。
- LD_KEEPDIR
- (a.out のみ)(libc5)
ロードする a.out
ライブラリの名前において、ディレクトリを無視しない。
このオプションは用いるべきではない。
- LD_NOWARN
- (a.out のみ)(libc5) a.out
ライブラリにおけるマイナーバージョン番号の非互換に
対する警告メッセージを抑制する。
- LD_ORIGIN_PATH
- (glibc 2.1 以降)
バイナリへのパス
(set-user-ID
されていないプログラムについて)。
セキュリティ上の理由から、glibc
2.3.4 以降、 set-user-ID/set-group-ID
されたバイナリでは
LD_ORIGIN_PATH
は無視される。
- LD_POINTER_GUARD
- (glibc 2.4 以降) 0
に設定すると、ポインター保護
(pointer guarding)
が無効になる。
それ以外の値の場合はポインター保護が有効になる。
デフォルトはポインター保護有効である。
ポインター保護はセキュリティ機構の一つで、書き込み可能なプログラムメモリー
に格納されたコードへのポインターをほぼランダム化することで、
攻撃者がバッファーオーバーランやスタック破壊
(stack-smashing) 攻撃の際に
ポインターを乗っ取ることを困難にするものである。
- LD_PROFILE
- (glibc 2.1 以降)
プロファイルを行う共有オブジェクトの名前。
パス名か共有オブジェクト名
(soname) で指定される。
プロフィールの出力は
" $LD_PROFILE_OUTPUT/$LD_PROFILE.profile"
という名前の
ファイルに追記される。
- LD_PROFILE_OUTPUT
- (glibc 2.1 以降) LD_PROFILE
の出力が書き込まれるディレクトリ。
この変数が定義されていないか、空の文字列が定義されている場合、
デフォルト値は /var/tmp
となる。 set-user-ID/set-group-ID
されたプログラムでは、
LD_PROFILE_OUTPUT は無視される。
出力ファイルは常に
/var/profile
が使用される。
- LD_SHOW_AUXV
- (glibc 2.1 以降)
カーネルから渡される補助的な
(パラメーターの)
配列を表示する。
セキュリティ上の理由から、glibc
2.3.4 以降、 set-user-ID/set-group-ID
されたバイナリでは
LD_SHOW_AUXV
は無視される。
- LD_USE_LOAD_BIAS
- デフォルトでは
(つまり、この変数が定義されていない場合)、
実行ファイルと prelink
された共有オブジェクトでは、それらが依存する
ライブラリのベースアドレスが尊重される一方、
(prelink されていない)
position-independent executables (PIEs) と
他の共有オブジェクトでは依存するライブラリのベースアドレスは
尊重されない。
LD_USE_LOAD_BIAS が値 1
で定義された場合、実行ファイルと
PIE のどちらでも
ベースアドレスが尊重される。
LD_USE_LOAD_BIAS が値 0
で定義された場合、実行ファイルと
PIE のどちらでも
ベースアドレスは尊重されない。
set-user-ID や set-group-ID
されたプログラムでは、
この変数は無視される。
- LD_VERBOSE
- (glibc 2.1 以降)
空文字列でない場合に、
LD_TRACE_LOADED_OBJECTS
環境変数が設定されていれば、プログラムのシンボルバージョン情報を出力する。
- LD_WARN
- (ELF のみ)(glibc 2.1.3 以降)
空文字列でない場合、解決されていないシンボルがあれば警告を出す。
- LDD_ARGV0
- (libc5) ldd(1)
の引き数がない場合に、
argv[0]
として使われる値。
- /lib/ld.so
- a.out
の動的リンカー/ローダー
-
/lib/ld-linux.so.{1,2}
- ELF
の動的リンカー/ローダー
- /etc/ld.so.cache
- ライブラリを検索するディレクトリを集めたリストと、
共有ライブラリの候補の整列リストを含むファイル。
- /etc/ld.so.preload
- プログラムの前にロードすべき
ELF 共有ライブラリを
スペースで区切ったリストが書かれているファイル。
- lib*.so*
- 共有ライブラリ
ld.so の機能は libc
のバージョン 4.4.3
以上を用いてコンパイルされた
実行ファイルで使用可能である。
ELF の機能は Linux 1.1.52 以降と
libc5
以降で使用可能である。
ld(1),
ldd(1),
pldd(1),
sprof(1),
dlopen(3),
getauxval(3),
rtld-audit(7),
ldconfig(8),
sln(8)
この man ページは Linux
man-pages
プロジェクトのリリース
3.79 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。