静的ライブラリ(.a)インスペクター
.a は ar アーカイブです。8 バイトのマジックのあと、メンバーごとに 60 バイトの固定幅 ASCII ヘッダー(名前 16、更新時刻 12、uid 6、gid 6、8 進数のモード 8、10 進数のサイズ 10)が並び、その後ろにメンバーのデータが偶数オフセットに揃えて続きます。このツールはそれをバイトから読み取り、ヘッダーの位置、データが実際に始まる位置、サイズ、UTC の時刻、所有者、パーミッションをメンバーごとに示します。16 バイトの欄に収まらない名前は別の場所に置かれ、その方法が二通りあります。GNU は長い名前を // というメンバーにまとめ、ヘッダーには /オフセット と書きます。BSD と macOS は #1/長さ と書き、名前をメンバーのデータの先頭に置きます。つまりデータはヘッダーの直後から始まらず、サイズ欄には名前の分も含まれます。15 文字までは "名前/" の形でヘッダーに収まりますが 16 文字は収まりません。この境目を読み違えると以降のオフセットがすべてずれるため、どちらの方式かと、各メンバーの名前がどこから来たかを明示します。ただし本題はシンボルインデックスです。/ という名前のメンバー(あるいは /SYM64/、BSD なら __.SYMDEF)は、シンボルからそれを定義するメンバーのファイルオフセットへの対応表にすぎず、ranlib 以外にそれを最新に保つものはありません。アーカイブをその場で編集したり、スクリプトで組み立てたり、インデックスを作り直さずにメンバーを追記したりすると、インデックスがもうそのシンボルを定義していないメンバーを指したり、すぐそこにあるシンボルを取りこぼしたりします。インデックスを信じるリンカは、アーカイブの中にあるシンボルに対して undefined reference を出します。だからこのツールは両方を読みます。インデックスと、各メンバー自身の ELF シンボルテーブルです。食い違いは項目ごとに並べます。ELF メンバーごとに、定義しているグローバルシンボルを nm と同じ文字とともに、未定義のまま残しているシンボルとあわせて示すので、メンバー同士の依存順序が読み取れます。二つのメンバーが強く定義しているシンボルは別に集めます。リンクが失敗する "duplicate symbol" がそれであり、ウィークシンボルやコモン、ユニークシンボルは本来繰り返されるものなので指摘しません。ELF でないメンバー(別プラットフォームの Mach-O や COFF、入れ子のアーカイブ、間違って入れたテキストファイル)は中途半端に解釈せずそう名指しし、メンバーがディスク上のファイルへの参照でしかない thin アーカイブもそう報告します。ただし、あるリンクが実際にどのメンバーを取り込むかは分かりません。それはリンク順と、その時点で何が未定義かに左右されます。
使い方
- .a ファイルをボックスにドロップします。何もアップロードされず、ページ内の JavaScript が読み取ります。
- 概要で名前の方式(GNU の // か BSD の #1/ か)、シンボルインデックスの種類、ファイルのうちどれだけがコードではなくインデックスと長い名前のテーブルかを確認します。
- まず「インデックスとメンバーの照合」を見ます。緑ならキャッシュとメンバーが一致し、赤なら食い違っているシンボルとメンバーをそのまま示します。
- メンバー表でヘッダーとデータの位置、サイズ、保存された日付を眺めます。再現可能なビルドは時刻と uid、gid を 0 で書くので、それ以外の値なら ar U で作られたアーカイブです。
- 「メンバーごとのシンボル」でメンバーを開き、何を定義し何をまだ必要としているかを見て、重複の一覧で "duplicate symbol" のリンクエラーを説明します。
よくある質問
- "archive has no index; run ranlib to add one" とは何ですか?
- そのアーカイブがシンボルテーブルなしで作られたという意味です。たいていは ar rcS で作ったか、ar q で追記したか、ar 形式を自分で書くツールが作ったものです。インデックスがないとリンカは何が定義されているか知るために全メンバーを開かねばならないので、多くは拒否して ranlib を求めます。ranlib は / という名前の先頭メンバーに対応表を入れます。ファイルに ranlib を実行するか ar s を使えばその場で直り、最初から ar rcs で作れば済みます。このツールはそうしたアーカイブに「シンボルインデックス: なし」と表示しますが、インデックスは高速化のためのものなのでメンバー一覧はそのまま読めます。
- ar がインデックスを更新するのに、なぜ古くなることがあるのですか?
- ar はアーカイブを書き直すたびにインデックスを作るので、普通のコマンドなら安全です。古くなるのは別のものがファイルに触ったときです。スクリプトがその場で書き換えた、ビルドシステムが ar q で追記して ranlib を回さなかった、ar 形式を自分で書くツールが組み立てた、別のマシンに移して編集した、といった場合です。インデックスは名前ではなくバイトオフセットを保存するので、作り直さずにメンバーが変わると、そのシンボルをもう定義していないバイトを指す項目が残ります。リンカはインデックスを信じるため、失敗は遠く離れた場所で、nm で見れば明らかにあるシンボルへの undefined reference として現れます。
- GNU と BSD の .a はどう違い、thin アーカイブとは何ですか?
- 違うのは 16 文字を超える名前とシンボルインデックスの置き方だけです。GNU は長い名前を // メンバーにまとめてオフセットで参照し、インデックスを / または 64 ビット版の /SYM64/ と呼びます。BSD は名前欄に #1/長さ と書いて名前をメンバーデータの先頭に置き、インデックスを __.SYMDEF あるいは __.SYMDEF SORTED と呼びます。したがってメンバーデータの開始位置が両者で変わり、これがアーカイブを読み違える最大の原因です。thin アーカイブは ar T が作る third の形式で、!<thin> で始まりヘッダーだけを保存し、データはディスク上の .o に残します。そのため .a だけを移動すると壊れます。
- メンバーに未定義シンボルがありますが、ライブラリが壊れているのですか?
- いいえ、正常であり、その一覧こそが要点です。メンバーはそれぞれ別のオブジェクトファイルで、未定義シンボルは他のメンバーや別のライブラリ、あるいはプログラム自身が用意してくれることを期待しているものです。あわせて読むとアーカイブ内の依存順序が分かります。静的ライブラリは統合されるのではなく検索されるので、これは重要です。リンカはコマンドラインを一度だけたどり、その時点で未定義のものを解決するメンバーだけを取り込むため、遅れて取り込まれたメンバーが、先に来ていたライブラリなら満たせたはずのシンボルを未定義のまま残すことがあります。リンク順が問題になり --start-group が存在する理由です。
- なぜ繰り返されたシンボルの一部だけを重複として報告するのですか?
- 一部だけがリンクを壊すからです。同じ名前を二つのメンバーが強く定義すると典型的な "duplicate symbol" エラーになります。しかしウィークな定義(nm の W と V)、コモンシンボル(C)、GNU のユニークシンボル(u)は繰り返される前提のものです。C++ のインライン関数やテンプレート、vtable はそれを使うすべてのオブジェクトに出力され、リンカが一つだけ残します。実際の libstdc++.a にはそうした繰り返しが数千あってもエラーになりません。全部並べると肝心の一件が埋もれるので、二つ以上のメンバーで強く定義された名前だけを集めています。
- アーカイブはどこかにアップロードされますか?
- いいえ。ブラウザの File API で読み、ページ内の JavaScript が解析します。送る先のサーバーが存在しません。静的ライブラリでは特に重要で、ベンダーや社内ビルドの .a はアップロードしてよいファイルとは限らないからです。ページを読み込んだあとネットワークを切っても動作し、ファイルはタブの外に出ません。
関連ツール
NumPy .npy / .npz インスペクター
.npy・.npz のヘッダーをブラウザで読み取ります。dtype、shape、バイト順、フィールド配置、先頭の値まで。NumPy もアップロードも不要です。
Mbox アーカイブビューア
mbox アーカイブをブラウザーで分割。メッセージ境界、デコード済みヘッダー、MIME 構造、スレッド、重複 Message-ID を表示し、アップロードはしません。
ZIP 内容ビューア
ZIP をドロップすると展開せずに中身を一覧・サイズ・プレビュー・個別ダウンロード可能。
HAR ファイルインスペクター (HTTP Archive ビューア)
Chrome / Firefox / Safari DevTools からエクスポートした .har ファイルをドロップすれば、すべてのリクエスト — メソッド、ステータス、サイズ、時間、コンテンツタイプ — を即座に表示。統計、最遅・最大テーブル、フィルター・ソート可能なエントリ。すべてブラウザ内処理。
DNS ゾーンファイル検証ツール
BIND のゾーンファイルを貼り付けると実際の意味がわかります。すべての名前を完全修飾で展開し、SOA を解説し、パーサーだけでは見つからない罠を指摘します。
Python pickle インスペクター
.pkl ファイルをブラウザで逆アセンブル。全オペコード、メモ、復元された値、そして読み込むとコードが走るかどうかまで。