Linuxの動的リンクとは?実行時に共有ライブラリを読み込む仕組みを初心者向けに解説
生徒
「Linuxの動的リンクって、プログラムを実行するときに何をしているんですか?」
先生
「動的リンクでは、実行ファイルの外にある共有ライブラリを利用して、必要な機能を実行時に使えるようにします。」
生徒
「ライブラリの中身を実行ファイルへ全部入れておくわけではないんですね?」
先生
「その通りです。Linuxでは動的リンカや動的ローダが必要な共有ライブラリを探して読み込みます。静的リンクとの違いも含めて基本から確認していきましょう。」
Linuxを初めて学ぶ人や、 OS・プロセス・メモリ管理・仮想マシン・コンテナの仕組みを図解で理解したい人におすすめの定番書籍です。
試して理解 Linuxのしくみを見る※ Amazonアソシエイト広告リンク
1. Linuxの動的リンクとは?
Linuxの読み方はLinux(リナックス)です。動的リンクの読み方は動的リンク(ドウテキリンク)で、英語ではdynamic linking(ダイナミックリンキング)といいます。動的リンクとは、プログラムが利用するライブラリのコードをすべて実行ファイルへ組み込まず、実行時に外部の共有ライブラリを利用できるようにする仕組みです。
ライブラリの読み方はlibrary(ライブラリ)です。プログラムで繰り返し使われる処理をまとめた部品集のようなもので、文字列処理、入出力、計算、通信など、さまざまな機能がライブラリとして提供されています。Linuxでは、多くのコマンドやアプリケーションが共有ライブラリを利用しています。
初心者の方は、動的リンクを「必要な道具を全部自分のかばんへ入れて持ち歩くのではなく、必要になったときに共通の道具置き場から借りる仕組み」と考えるとわかりやすいでしょう。複数のプログラムが同じ共有ライブラリを利用できるため、同じコードを実行ファイルごとに持たせる必要を減らせます。
なお、動的リンクという言葉のリンクは、ファイルやディレクトリを指し示すシンボリックリンクとは意味が異なります。ここではプログラムとライブラリを結び付ける処理を意味します。
2. 共有ライブラリとは?soファイルの役割
共有ライブラリの読み方は共有ライブラリ(キョウユウライブラリ)です。英語ではshared library(シェアードライブラリ)と呼ばれ、複数のプログラムから共通して利用できるライブラリです。Linuxでは、ファイル名に.soが付いた共有ライブラリをよく見かけます。
soはshared object(シェアードオブジェクト)に由来する名称です。たとえばlibexample.soのような名前が使われます。実際のLinuxでは、互換性やバージョン管理のために、末尾へ数字が付いた共有ライブラリも多くあります。
動的リンクされた実行ファイルには、通常、必要な共有ライブラリについての情報が記録されています。プログラムを起動すると、動的リンカや動的ローダがその情報を確認し、必要な共有ライブラリを探してメモリへ読み込みます。その後、プログラムから呼び出される関数と共有ライブラリ側の関数を対応付けます。
共有ライブラリを利用すると、同じ機能を複数の実行ファイルへ重複して組み込む量を減らしやすくなります。また、同じ共有ライブラリのコード部分を複数のプロセスで共有できる場合があるため、Linuxで多数のプログラムを動かす環境でも効率的に利用できます。
Linuxの動的リンクを理解するときは、実行ファイル、共有ライブラリ、動的リンカ、動的ローダという四つの関係を意識すると仕組みが見えやすくなります。
3. 静的リンクと動的リンクの違い
動的リンクと比較される仕組みに静的リンクがあります。静的リンクの読み方は静的リンク(セイテキリンク)で、英語ではstatic linking(スタティックリンキング)といいます。静的リンクでは、プログラムを作る段階で必要なライブラリのコードを実行ファイル側へ取り込みます。
一方の動的リンクでは、共有ライブラリを実行ファイルの外に置き、プログラムを動かすときに利用します。そのため、動的リンクされた実行ファイルは、同じ機能を静的にすべて組み込んだ場合と比べて小さくなることがあります。
共有ライブラリを一か所で管理できる点も特徴です。互換性を保ったまま共有ライブラリを更新できれば、複数のプログラムが修正版を利用できる場合があります。静的リンクの場合は、ライブラリを更新しても、すでに実行ファイルへ組み込まれたコードが自動的に新しくなるわけではないため、再ビルドが必要になります。
ただし動的リンクには、実行環境に必要な共有ライブラリが存在しなければプログラムを起動できないことがあるという注意点があります。Linuxで「共有ライブラリが見つからない」というエラーが表示される場合は、動的リンクの依存関係やライブラリの検索場所が原因になっていることがあります。
4. gccで動的リンクされたプログラムを作る基本
LinuxでC言語のプログラムを作るときは、GCCを利用することがあります。GCCの読み方はGCC(ジーシーシー)です。GCCはC言語などのソースコードをコンパイルし、実行ファイルを作るために利用される処理系です。
一般的なLinux環境では、特別に静的リンクを指定せずに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(コンパイル)です。ソースコードをコンピュータが扱える形へ変換する処理です。その後、必要なライブラリなどを結び付けるリンク処理を経て、実行可能なプログラムが完成します。GCCを使うと、これらの処理をまとめて行うことができます。
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の種類、システム構成によって異なります。
依存関係の読み方は依存関係(イゾンカンケイ)です。プログラムが別のライブラリや機能を必要としている関係を意味します。Linuxでアプリケーションが起動しないときに、どの共有ライブラリが必要なのかを調べる作業では、依存関係の確認が重要です。
なお、出所が不明な実行ファイルを調べる場合には注意が必要です。学習するときは、自分でコンパイルした実行ファイルを対象にしてlddの表示を確認すると安全でわかりやすいでしょう。
6. readelfで実行ファイルが必要とするライブラリを確認する
動的リンクの情報をさらに詳しく確認するときは、readelfコマンドも利用できます。readelfの読み方はreadelf(リードエルフ)です。Linuxでよく使われる実行ファイル形式であるELFの情報を調べるためのコマンドです。
ELFの読み方はELF(エルフ)で、Executable and Linkable Format(エグゼキュータブルアンドリンカブルフォーマット)の略です。Linuxでは実行ファイルや共有ライブラリなどで広く利用されています。
次のように実行すると、実行ファイルが必要としている共有ライブラリの情報を確認できます。
readelf -d ./hello | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
NEEDEDは、その実行ファイルが必要とする共有ライブラリを示す情報です。この例ではlibc.so.6が必要であることを確認できます。
lddは実際にどこからライブラリが見つかるか確認しやすく、readelfは実行ファイル内部に記録された情報を調べるのに便利です。初心者はまずlddを覚え、そのあとELFやリンク処理を詳しく学ぶときにreadelfへ進むと理解しやすいでしょう。
7. 動的リンカと動的ローダは何をしている?
Linuxで動的リンクされたプログラムを起動すると、必要な共有ライブラリを準備する処理が行われます。この処理で重要な役割を持つのが動的リンカや動的ローダです。動的ローダの読み方は動的ローダ(ドウテキローダ)で、英語ではdynamic loader(ダイナミックローダ)といいます。
動的ローダは、実行ファイルが必要とする共有ライブラリを確認し、決められた検索方法に従ってライブラリを探し、メモリへ読み込みます。さらに、プログラム内で使われる関数や変数と、共有ライブラリ側にある実体を対応付ける処理にも関係します。
初心者の方は、プログラムの起動時に「このプログラムにはこの部品が必要」と書かれた一覧を確認し、Linuxが必要な部品を保管場所から集めて準備しているイメージを持つとよいでしょう。
必要な共有ライブラリが見つからない場合は、プログラムの本体が存在していても正常に起動できません。つまり、動的リンクされた実行ファイルだけを別のLinux環境へコピーしても、必要な共有ライブラリがそろっていなければ動作しない場合があります。
8. 自作の共有ライブラリを動的リンクして使う方法
Linuxでは、自分で共有ライブラリを作成して、それを別のプログラムから動的に利用することもできます。ここでは足し算を行う簡単な関数を共有ライブラリにしてみましょう。
共有ライブラリを作るときには、-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
この操作によってlibcalc.soという共有ライブラリが作られます。次に、このライブラリに入っているadd関数を使うプログラムを作ります。
printf '#include <stdio.h>\nint add(int, int);\nint main(void){printf("%d\\n", add(20, 30));return 0;}\n' > main.c
gcc main.c -L. -lcalc -Wl,-rpath,'$ORIGIN' -o calc-app
./calc-app
50
-L.は現在のディレクトリをライブラリの検索対象に加える指定です。-lcalcではlibcalc.soという名前のライブラリを利用するよう指定しています。$ORIGINを使った設定では、実行ファイルが置かれている場所を基準として共有ライブラリを探せるようにしています。
実務では共有ライブラリをシステム標準の場所へ配置したり、アプリケーション専用のディレクトリへ配置したりするなど、さまざまな方法があります。初心者の学習では、実行ファイルと共有ライブラリを同じ場所へ置いて関係を確認すると理解しやすくなります。
9. 動的リンクのメリットと注意点
Linuxで動的リンクを利用するメリットの一つは、共有ライブラリを複数のプログラムから共通利用できることです。同じライブラリのコードを各実行ファイルへすべて組み込む必要を減らせるため、実行ファイルを小さくしやすくなります。
また、互換性を保った共有ライブラリに修正が行われた場合、共有ライブラリを更新することで複数のプログラムが新しいコードを利用できる場合があります。セキュリティ上の問題が修正された共有ライブラリへ更新すると、多くのプログラムで修正版を利用できることも動的リンクの重要な特徴です。
一方で、共有ライブラリへの依存があるため、必要なライブラリが削除されたり、検索できない場所へ移動したり、互換性のないバージョンになったりすると、プログラムが起動できないことがあります。そのためLinuxでは、共有ライブラリのバージョンや保存場所を適切に管理する必要があります。
共有ライブラリの検索に関係するものとしてLD_LIBRARY_PATHという環境変数があります。環境変数の読み方は環境変数(カンキョウヘンスウ)です。現在の設定は次のように確認できます。
echo "$LD_LIBRARY_PATH"
/home/user/mylibs
ただし、LD_LIBRARY_PATHを意味を理解せずに変更すると、想定していない共有ライブラリが使われるなどの問題につながる場合があります。本番サーバーでは、インターネット上の設定例をそのままコピーするのではなく、ライブラリの検索方法やアプリケーションの構成を確認して設定することが大切です。
Linux初心者が動的リンクを学ぶときは、まず「実行ファイルは必要な共有ライブラリの情報を持っている」「プログラムの実行時にLinuxが共有ライブラリを探して読み込む」「lddやreadelfで依存関係を確認できる」という三つの流れを理解するとよいでしょう。
Linuxの動的リンクは、実行時に共有ライブラリを利用できるようにする仕組みです。共有ライブラリ、soファイル、動的リンカ、動的ローダ、依存関係、静的リンクとの違いを一緒に学ぶことで、Linuxでプログラムが起動するときの仕組みを理解しやすくなります。