Linuxのダイナミックリンクとは?共有ライブラリを利用する動的リンクの仕組みを初心者向けに解説
生徒
「Linuxのダイナミックリンクって、どんな仕組みなんですか?」
先生
「ダイナミックリンクは、プログラムの実行時に共有ライブラリを利用する仕組みです。必要な機能を実行ファイルの外にあるライブラリから読み込みます。」
生徒
「静的リンクとは何が違うんですか?」
先生
「静的リンクは必要なコードを実行ファイルへ組み込む方式ですが、動的リンクは共有ライブラリを外部に置いて利用します。Linuxでの確認方法や作り方も含めて順番に見ていきましょう。」
Linuxを初めて学ぶ人や、 OS・プロセス・メモリ管理・仮想マシン・コンテナの仕組みを図解で理解したい人におすすめの定番書籍です。
試して理解 Linuxのしくみを見る※ Amazonアソシエイト広告リンク
1. Linuxのダイナミックリンクとは?
Linuxの読み方はLinux(リナックス)です。ダイナミックリンクは英語でdynamic linking(ダイナミックリンキング)といい、日本語では動的リンク(ドウテキリンク)と呼ばれます。動的リンクとは、プログラムが必要とする機能をすべて実行ファイルへ組み込むのではなく、実行時に共有ライブラリを利用できるように結び付ける仕組みです。
ライブラリの読み方はlibrary(ライブラリ)です。プログラミングでは、よく使う関数や処理をまとめた部品集をライブラリと呼びます。たとえば文字を画面へ表示する処理や、文字列を扱う処理などを毎回すべて自分で作るのではなく、すでに用意されたライブラリの機能を利用できます。
Linuxでは、共有ライブラリのファイル名に.soが付くものをよく見かけます。soはshared object(シェアードオブジェクト)に由来する名前です。複数のプログラムが同じ共有ライブラリを利用できるため、共通の機能を効率よく管理できます。
初心者の方は、共有ライブラリを「みんなで使う共通の道具箱」と考えるとわかりやすいでしょう。各プログラムが同じ道具を自分の中へ一式コピーするのではなく、必要になったときに共通の道具箱を利用するイメージです。
ダイナミックリンクのリンクは、ファイルへのショートカットを作るシンボリックリンクとは別の意味です。ここでは、プログラムと共有ライブラリを結び付ける仕組みを表します。
2. 共有ライブラリとは?soファイルの役割
共有ライブラリの読み方は共有ライブラリ(キョウユウライブラリ)で、英語ではshared library(シェアードライブラリ)といいます。Linuxでは、複数の実行プログラムから共通して利用できるライブラリとして使われます。
代表的な共有ライブラリには、C言語の基本的な機能を提供するライブラリなどがあります。実行ファイル側には、利用する関数のコードをすべて持たせるのではなく、どの共有ライブラリを必要とするかという情報が記録されます。そしてプログラムを起動するときに、Linuxの仕組みが必要な共有ライブラリを探して読み込みます。
.soという拡張子のファイルは、Linuxで共有オブジェクトとして利用される代表的な形式です。実際にはlibexample.soのような名前だけでなく、互換性を管理するためにバージョン番号が付いた名前もよく使われます。
共有ライブラリを使う大きな理由の一つは、同じ機能を複数の実行ファイルへ重複して組み込む必要を減らせることです。多くのプログラムが同じライブラリを利用する環境では、実行ファイルの容量やメモリ利用を抑えやすくなります。
3. 静的リンクと動的リンクの違い
動的リンクと比較される仕組みに静的リンクがあります。静的リンクの読み方は静的リンク(セイテキリンク)で、英語ではstatic linking(スタティックリンキング)といいます。静的リンクでは、ビルドするときに必要なライブラリのコードを実行ファイル側へ取り込みます。
動的リンクでは、実行ファイルの外に共有ライブラリを置き、プログラムの起動時などに必要なライブラリを読み込みます。そのため、同じ共有ライブラリを複数のプログラムで使いやすいことが特徴です。
一方、実行環境に必要な共有ライブラリが存在しなかったり、要求するバージョンと合わなかったりすると、動的リンクされたプログラムが起動できない場合があります。Linuxで「共有ライブラリが見つからない」というエラーが表示されるのは、このような依存関係が原因になることがあります。
静的リンクは実行ファイルが大きくなりやすい代わりに、外部の共有ライブラリへの依存を減らしやすい方式です。動的リンクは実行ファイルを小さくしやすく、ライブラリを共通化しやすい方式です。Linuxでは用途に応じて両方の方法が使われています。
4. gccで動的リンクされた実行ファイルを作る方法
LinuxでC言語のプログラムをコンパイルするときは、GCCを利用することがあります。GCCの読み方はGCC(ジーシーシー)です。一般的なLinux環境では、特別に静的リンクを指定しなければ、標準ライブラリなどを動的に利用する形で実行ファイルが作られることがあります。
次の例では、画面へ文字を表示する小さなC言語プログラムを作成し、gccで実行ファイルへ変換します。
printf '#include <stdio.h>\nint main(void){printf("Hello Linux\\n");return 0;}\n' > hello.c
gcc hello.c -o hello
./hello
Hello Linux
この例ではhello.cからhelloという実行ファイルを作っています。プログラム内では文字を表示するために標準ライブラリの機能を利用しています。環境によって詳細は異なりますが、このような通常のビルドでは共有ライブラリを利用する実行ファイルが作られることがあります。
コンパイルの読み方はcompile(コンパイル)です。ソースコードをコンピュータが扱える形へ変換する処理を表します。その後に必要なライブラリを結び付けるリンク処理が行われ、実行ファイルが完成します。
5. lddコマンドで利用する共有ライブラリを確認する
Linuxで実行ファイルがどの共有ライブラリを必要としているか調べたいときは、lddコマンドが便利です。lddの読み方はldd(エルディーディー)です。動的リンクされた実行ファイルが依存している共有ライブラリを一覧で確認できます。
ldd ./hello
linux-vdso.so.1
libc.so.6 => /lib64/libc.so.6
/lib64/ld-linux-x86-64.so.2
この表示では、libc.so.6などが実行時に利用される共有ライブラリとして確認できます。実際のライブラリ名や保存場所は、Ubuntu、Debian、AlmaLinuxなどのLinuxディストリビューションやCPUの種類によって異なります。
ディストリビューションの読み方はdistribution(ディストリビューション)です。Linuxカーネルとさまざまなソフトウェアを組み合わせ、利用しやすい形で提供しているものを指します。環境によって共有ライブラリの配置場所が異なることがあるため、lddの結果を実際に確認することが重要です。
なお、信頼できない実行ファイルを調査するときは、安易に実行するのではなく、readelfなど実行せずに情報を確認できる方法も利用します。Linuxの学習では、自分で作った実行ファイルを使ってlddの表示に慣れるとよいでしょう。
6. 自分で共有ライブラリを作って動的リンクする方法
Linuxでは、自分で共有ライブラリを作成してプログラムから利用することもできます。次の例では、二つの数値を足し算するadd関数を共有ライブラリへまとめます。
共有ライブラリを作成するときは、GCCの-fPICと-sharedを利用する方法があります。PICの読み方はPIC(ピック)で、Position Independent Code(ポジションインディペンデントコード)の略です。共有ライブラリとして利用しやすい位置独立コードを作るために使われます。
printf 'int add(int a, int b){return a + b;}\n' > add.c
gcc -fPIC -c add.c -o add.o
gcc -shared add.o -o libcalc.so
ls -l libcalc.so
-rwxr-xr-x 1 user user 15016 Aug 10 08:00 libcalc.so
この例では、まずadd.cからadd.oというオブジェクトファイルを作っています。そのあと-sharedを指定し、libcalc.soという共有ライブラリを作成しています。
オブジェクトファイルの読み方はobject file(オブジェクトファイル)です。ソースコードをコンパイルしたあと、最終的な実行ファイルやライブラリになる前の部品として使われます。小さな例で実際に作ってみると、共有ライブラリが特別な魔法ではなく、再利用するコードをまとめたファイルであることが理解しやすくなります。
7. 作成したsoファイルをプログラムから利用する方法
作成したlibcalc.soを別のプログラムから利用してみましょう。共有ライブラリをリンクするときは、GCCの-Lや-lを利用できます。-L.は現在のディレクトリをライブラリの検索場所へ追加し、-lcalcはlibcalc.soというライブラリを探してリンクする指定です。
printf '#include <stdio.h>\nint add(int, int);\nint main(void){printf("%d\\n", add(10, 20));return 0;}\n' > main.c
gcc main.c -L. -lcalc -Wl,-rpath,'$ORIGIN' -o calc-app
./calc-app
30
この例ではcalc-appが実行時に同じディレクトリにあるlibcalc.soを利用できるよう、実行ファイル側へライブラリ検索場所の情報を持たせています。$ORIGINは実行ファイル自身が置かれているディレクトリを基準にするための表現です。
実務では、共有ライブラリをシステムの標準的な場所へ配置したり、アプリケーション専用ディレクトリから読み込ませたりするなど、さまざまな管理方法があります。初心者の学習では、まず実行ファイルと共有ライブラリを同じ作業ディレクトリへ置き、どのように結び付いているのか確認すると理解しやすいでしょう。
8. 動的ローダと共有ライブラリの検索方法
動的リンクされたプログラムを起動するときは、必要な共有ライブラリを探して読み込む仕組みが働きます。この役割に関係するものを動的ローダと呼びます。動的ローダの読み方は動的ローダ(ドウテキローダ)で、英語ではdynamic loader(ダイナミックローダ)といいます。
Linuxでは、実行ファイルに記録された情報やシステムの設定などをもとに共有ライブラリが検索されます。一般的なライブラリの保存場所や、実行ファイルに設定された検索パスなどが利用されます。環境によってはLD_LIBRARY_PATHという環境変数も検索に影響します。
環境変数の読み方は環境変数(カンキョウヘンスウ)です。プログラムの動作に影響する設定値を名前と値の組み合わせで保持する仕組みです。現在の値は次のように確認できます。
echo "$LD_LIBRARY_PATH"
/home/user/mylibs
ただし、LD_LIBRARY_PATHを無計画に設定すると、意図していない共有ライブラリが優先されるなど、トラブルの原因になる場合があります。特に管理者権限で動くシステムや本番サーバーでは、意味を理解せずに変更しないことが大切です。
Linux初心者は、まず「実行ファイルが共有ライブラリを必要とし、起動時にLinuxの仕組みが適切なライブラリを探して読み込む」と理解しておけばよいでしょう。
9. ダイナミックリンクのメリットと注意点
ダイナミックリンクの大きなメリットは、複数のプログラムで共有ライブラリを共通利用できることです。各実行ファイルへ同じライブラリのコードをすべて組み込む必要がないため、実行ファイルを小さくしやすくなります。また、同じ共有ライブラリを複数のプロセスが利用する場合、メモリ上のコード部分を共有できることもあります。
共有ライブラリ側の不具合やセキュリティ上の問題を修正した場合、互換性が保たれていれば、共有ライブラリを更新することで複数のプログラムへ修正を反映できる場合があります。静的リンクされたプログラムでは、組み込み済みのライブラリを更新するために実行ファイルを再ビルドする必要があるため、この点は大きな違いです。
一方で、必要な共有ライブラリが削除されたり、互換性のないバージョンへ変わったりすると、プログラムが起動できなくなることがあります。そのためLinuxでは、共有ライブラリの名前やバージョン、検索パス、依存関係を適切に管理することが大切です。
歴史的にも、コンピュータで多数のプログラムを利用するようになると、同じライブラリコードを各実行ファイルへ持たせるより、共通化して利用する仕組みが重要になりました。現在のLinuxでも、多くのコマンドやアプリケーションが共有ライブラリと動的リンクの仕組みを利用しています。
Linuxのダイナミックリンクは、実行時に共有ライブラリを利用する動的リンクの仕組みです。.soファイル、ldd、GCC、動的ローダ、静的リンクとの違いを一緒に学ぶと、Linuxでプログラムがどのようにライブラリを利用しているのか理解しやすくなります。