LinuxにもWindowsのDLL(ダイナミックリンクライブラリ)のような仕組みはあるのですか?
あります。Linux(やUNIXの世界)では共有ライブラリなどと呼ばれることが多いようです。実際の解説に入る前に,なぜDLLあるいは共有ライブラリが必要なのか簡単にまとめておきましょう。
通常,アプリケーションはCやC++言語など高級言語で作成されています。これらの言語は,ある決まった処理に関しては,ライブラリという外部ファイルにサブルーチン群(関数)としてまとめられています。
例えば,画面に文字を出すprintfという関数があったとしましょう。筆者が書いたfooプログラムがこの関数を利用するとします。ダイナミックリンクを用いない(スタティックリンクといいます)場合,printfを処理するためのコードは,fooの実行ファイルの中に含められます。
一方,共有ライブラリを使う場合,fooの実行ファイルには「printfを含む共有ライブラリを使用する(メモリにロードする)」という情報と,ロードされたライブラリの中にあるprintf関数とfooの実行ファイルを結び付ける仕組みが組み込まれます。printfの実際の処理コードは共有ライブラリlibc.so(Cの標準関数が入っている共有ライブラリ)というファイルに入っており,fooを実行するとlibc.soがメモリに読み出され(詳しくは後述),libc.soの中にあるprintf処理コードが利用されます。
このような仕組みが利用される理由は一口にいえば「資源の有効利用」に尽きます。スタティックリンクしかないなら,例えばprintfを使うソフトが100個あれば,printfを処理するコードも100個,同じものをそれぞれの実行ファイルが持たなければなりません。また,メモリに実行ファイルを読み込んだときも,同じprintfの処理コードがいくつも存在することになり不経済です。共有ライブラリを使用すれば,printfを使うソフトがいくつあっても,実際の処理コードはシステムの中で一つしか必要がなくなり,ディスクやメモリの負担を減らすことができるのです。
さて,では実際にLinuxを使って,どのように共有ライブラリが実現されているかを実験で確かめてみることにします。実行ファイルが,どのライブラリ,どのバージョンをリンクしているか調べるlddコマンドを利用してみましょう。
画面1 lddコマンドでlsコマンドがリンクしているライブラリを調べてみる
画面1を見てください。lsコマンドがリンクしているライブラリはld.so.5で,その実体は/lib/libc.so.5であることが分かります。先に述べたように,libc.soはC言語の標準関数が入っている共有ライブラリで,末尾の5はバージョン番号です。lsコマンドは標準関数しか使わずに実装されていることが分かります(例示したLinuxは古いバージョンです。新しいもので実行するとlibc.so.6と表示されるかもしれません)。
もちろん,libc.soだけではなく,多くの共有ライブラリをリンクしている実行ファイルもあります(画面2)。
画面2 多くのライブラリをリンクしている実行ファイルの例
画面2はUNIX上の代表的なグラフィックツールの一つxvを調べた例です。X Window System のライブラリ(XLib)であるlibX11,TIFFフォーマットを操作するライブラリlibtiffなどをリンクしていることが確認できます。また,libc.soもリンクしています。UNIX上のソフトウェアは大部分がC言語で作成されているため,libcをリンクしていない実行ファイルは存在しないと考えても間違いではありません(だからこそ,libc.soのバージョンは非常に重要なのです)。
以上のように,実行ファイルがリンクしているライブラリのバージョンや場所は調べることができます。では,どのようにして共有ライブラリが実現されているのでしょうか。
やや複雑な話になるため簡単にまとめておきますが,実行ファイルを作成するときに,実行ファイルの中にそれが使用するライブラリの名前,使用する関数の名前(シンボル)に関する情報がまとめられた「共有オブジェクト」だけがリンクされます。実行ファイルをメモリにロードすると,ダイナミックリンカ(/lib/ld-linux.so.*)によって,共有ライブラリのシンボルと実行ファイルのシンボルが関連付けられるようになっています。
共有ライブラリのロード,アンロードは/lib/libdl.so.*に含まれる
などの関数で制御できます。実行ファイルがロードされ,ダイナミックリンカによって共有ライブラリがロードされた後,実行ファイルを終了すると,dlclose()によって共有ファイルの使用終了が宣言され,必要に応じてメモリから取り除かれるようになっています。
ちなみに,現在のLinuxは共有ライブラリや実行ファイルのフォーマットとしてELF(Execution Linking Format)を採用しています。ELFはUNIX System Laborato
ries (USL) がSystemV Release4(SVR4)に利用するために策定したフォーマットで,Windowsが採用しているCOFF(ELFの前身)に比べ柔軟で強力とされています。
例えば,ELFには初期化セクション,終了時セクションがあり,これらはC++言語のコンストラクタ,デコンストラクタの機構と厳密に一致するように作られています。したがって,ELFならばC++言語のクラスライブラリを共有ライブラリとして実装することも可能になっています。
(米田 聡)