🐧 Linux 総合学習プラットフォーム
C・ビルドツール ・ 上級

共有ライブラリの確認

Linuxの実行ファイルの多くは、共有ライブラリ(.so)を実行時に読み込む形でビルドされています。ldd ./prog と打つと、その実行ファイルがどの共有ライブラリに依存し、それぞれが実際にどのパスへ解決されているかを一覧できます。「not found」と表示されたら依存先が見つかっておらず、実行時エラーの原因になります。シンボル(関数や変数)の状況を見たいときは nm、より詳しい逆アセンブルや構造を見たいときは objdump を併用します。これらは配布された実行ファイルの素性を調べるときにも役立ちます。

Linuxの実行ファイルは、必要な機能をすべて自分の中に抱え込んでいるとは限りません。むしろ多くの場合、printf のようなありふれた関数の実体は、実行ファイルの外にある共有ライブラリに置かれていて、プログラムは起動するたびにそれを読み込んで使います。共有ライブラリは拡張子 .so で表され、shared object(共有オブジェクト)の略です。同じライブラリを多数のプログラムで共用できるため、それぞれの実行ファイルにライブラリを丸ごと埋め込む場合に比べ、ディスクとメモリを大きく節約できます。その代わり、実行時に必要な .so が見つからないと、プログラムは起動できずにエラーになります。この「外部の部品に依存して動く」という性質を理解し、依存関係を調べられるようになることが、実行ファイルの素性を見抜く鍵になります。

動的リンクと静的リンク

ライブラリの結びつけ方には2通りあります。1つは動的リンクで、共有ライブラリ(.so)を実行ファイル本体には含めず、起動時に動的リンカが読み込む方式です。Linuxの実行ファイルの多くはこの形でビルドされており、本体は小さく保たれ、ライブラリは複数のプログラムで共有されます。もう1つは静的リンクで、ライブラリの実体を実行ファイルの中に埋め込んでしまう方式です。この場合に使うのが静的ライブラリで、拡張子は .a です。静的リンクした実行ファイルは外部の .so に依存せず単体で動く反面、サイズが大きくなり、ライブラリを更新しても作り直すまで反映されません。組込みの分野では、依存を減らして配布を簡単にするためにあえて静的リンクを選ぶこともあり、両者は目的に応じて使い分けられます。

依存を一覧する ldd

ある実行ファイルが、どの共有ライブラリに依存しているかを調べるコマンドが ldd です。ldd ./prog のように実行ファイルを渡すと、それが必要とする .so の一覧と、それぞれが実際にどのパスへ解決されているかが表示されます。出力は libm.so.6 => /lib64/libm.so.6 のような形で、左が必要としているライブラリ名、矢印の右が実際に見つかった場所です。これを見れば、プログラムが裏でどんな部品に支えられて動いているかが一目で分かります。たとえば数学ライブラリを使うプログラムなら libm が、暗号を使うなら libssl や libcrypto が一覧に現れます。共有ライブラリの依存関係を確認したいときの第一手が、この ldd です。

not found が出たとき

ldd の出力で最も注意すべきは not found という表示です。あるライブラリ名の右側が => not found となっていたら、その依存先がシステム上で見つかっていないことを意味します。この状態のままプログラムを起動しようとすると、「共有ライブラリを開けない(error while loading shared libraries)」という実行時エラーになって起動に失敗します。原因の多くは、必要なライブラリがインストールされていない、あるいはインストールされてはいるが動的リンカの探索パスに含まれていない場所にある、というものです。対処としては、不足しているライブラリのパッケージを導入する、ライブラリの置き場所を探索パスに加える(設定ファイルや環境変数で指定し、必要に応じてキャッシュを更新する)といった方法があります。「動かないと思ったら、まず ldd で not found が無いか確認する」が定石です。

シンボルを調べる nm

ライブラリやオブジェクトファイルの「中身」、すなわちどんな関数や変数が入っているかを調べたいときは nm を使います。nm は、オブジェクトファイル(.o)や実行ファイル、ライブラリに含まれるシンボル(関数名や変数名)の一覧を表示するコマンドです。各シンボルには種別を表す記号が付き、たとえば T はそのファイル内で定義されている関数(テキストセクション)、U はこのファイルでは未定義で外部から与えられる必要があるシンボルを表します。リンク段階で undefined reference エラーが出たとき、nm で関係する .o を調べ、「その関数が U(未定義)のまま残っていないか」「定義しているはずの .o に T として存在するか」を突き合わせると、どこで実体が欠けているのかを切り分けられます。シンボルの過不足を確認するための地味ながら強力な道具です。

構造を読み解く objdump と ar

より深く、機械語のレベルまで踏み込んで調べたいときは objdump が役立ちます。objdump は実行ファイルやオブジェクトファイルの内部構造を詳しく表示するツールで、機械語を人間が読めるアセンブリへ戻す逆アセンブル(objdump -d)や、各セクションの情報、ヘッダの内容などを確認できます。コンパイラがどんな命令を生成したかを確かめたいときや、低レベルの挙動を追うときに使います。また、複数のオブジェクトファイルをまとめて1つの静的ライブラリ(.a)を作ったり、その中身を一覧・取り出したりするのが ar(archiver)です。ar は .a アーカイブの作成・更新・内容確認を担い、自前のライブラリを用意するときに使います。これらは普段の開発で毎回使うものではありませんが、いざというとき実行ファイルやライブラリの内部に分け入るための専門工具として知っておく価値があります。

実務での使いどころ

これらのツールが活きるのは、トラブル対応と素性調査の場面です。配布されたバイナリや、ビルドはできたのに実行時に落ちるプログラムに出くわしたとき、まず ldd で依存ライブラリと not found の有無を確かめ、リンク段階の謎には nm でシンボルの過不足を、より深い挙動の調査には objdump で中身を見る——という流れが基本になります。組込みLinuxでは、ターゲット機材に必要な共有ライブラリが揃っているか、依存が解決できるかが移植や配置の成否を左右するため、ldd による依存確認は特に重要です。「実行ファイルは外部の部品に依存して動く」という前提に立ち、その依存関係(ldd)・シンボル(nm)・内部構造(objdump)を調べる手段を持っておけば、ブラックボックスに見える実行ファイルの問題にも、根拠を持って立ち向かえるようになります。

この項目に出てくる用語

共有ライブラリきょうゆうらいぶらり
実行時に読み込まれる、複数プログラムで共用できるライブラリ(.so)。
オブジェクトファイルおぶじぇくとふぁいる
ソースを機械語へ変換した、リンク前の中間ファイル(.o)。
実行ファイルじっこうふぁいる
そのまま起動して動かせる、完成した機械語のプログラム。

関連コマンド

lddnmobjdumpar

▶ 学習アプリでこの続きを学ぶ・演習する