VPN インストーラーが 32 ビットと言うとき:代わりに ELF ヘッダーを確認する
語長は命令セットを特定しません。クラス、マシン、インタープリターを読み、ホストに合うビルドを要求する手順です。
ダウンロードページは 32 ビットと言い、ファイルは Raspberry Pi に届き、インストーラーは問題の役立つ部分を何も名指さないメッセージで失敗します。まったく異なる二つの実行ファイルがどちらも ELF の意味で 32 ビットと数えられ、そのボードで動くのは片方だけです。クラスフィールドは一つの事実、マシンフィールドは別の事実で、ファイル名はどちらも確実には教えてくれません。ライブラリを変えたり別のミラーを試したりする前に、ヘッダーを読みましょう。
クラスは語長を、マシンは命令セットを告げる
Linux の ELF リファレンスはファイルヘッダーにクラスフィールドとマシンフィールドを定義しており、両者は別の問いに答えます。クラスはそのファイルが 32 ビット形式か 64 ビット形式かを告げ、マシンはどの命令セット向けにビルドされたかを告げます。32 ビットの x86 ビルドと 32 ビットの ARM ビルドは前者で一致し、後者で食い違います。だからこそ、正しい語長をうたうラベルでも、プロセッサがデコードできないコードが届くのです。読む価値のある三つ目の値は要求されたインタープリターで、バイナリが宣言している場合にプログラムヘッダーがそれを名指します。
readelf -h -- ./vendor-vpn
readelf -l -- ./vendor-vpn
readelf -d -- ./vendor-vpn | grep NEEDED
最初のコマンドはヘッダーを、二番目はプログラムヘッダーがある場合にそれを出力し、三番目はローダーが必要とする共有オブジェクトを一覧します。クラス、マシン、インタープリターは、この三つの値がこの層での互換性の問いのすべてであるため、まとめて記録してください。三つのどれもダウンロードボタンには出ないので、ファイルは説明するのではなく検査する必要があります。
カーネルにどのインタープリターを要求するか
インタープリターを宣言する実行ファイルは、カーネルに特定のローダーパスを一つ要求します。そのローダーが無いと、名指したファイルがすぐそこにあっても起動は失敗します。ここで人々はダウンロードが壊れていると判断しますが、実際の答えはディストリビューションが提供しないローダーです。
ローダーは、実際に動かしているシステム(OS のリリース、ユーザー空間のアーキテクチャ、ローダーを提供するパッケージ)に合わせます。64 ビットのカーネルが 32 ビットのユーザー空間を動かせるのは、その空間とローダーが導入されている場合だけであり、プロセッサの能力が決め手ではありません。短い確認一回でインタープリターが一行に示され、サポートチケットより短い時間で済みます。シェルスクリプトは、インタープリターが ELF ヘッダーではなく一行目に書かれているため、また別の形で失敗し、その行を読むのに費用はかかりません。
file --brief ./vendor-vpn
ダウンロードをパッケージのアーキテクチャに合わせる
ディストリビューションのパッケージアーキテクチャは同じ区別を独自の語彙で符号化しており、ベンダーのサポート声明が指すのはその語彙です。マーケティング上のラベルをファイル名と比べるのではなく、パッケージマネージャーが報告する値をベンダーが文書化した値と比べてください。問題を起こす組は、どちらの組もダウンロード一覧では交換可能に見えるため、amd64 と arm64、armhf と armel です。x64 や ia32 で終わるファイル名はビルド対象を表し、それを保持するマシンを表しません。
| Label on the download | ELF class | e_machine | Interpreter the kernel wants | How it fails on the wrong host |
|---|---|---|---|---|
| amd64 | ELF64 | x86-64 | /lib64/ld-linux-x86-64.so.2 | Immediate exec failure on an ARM board |
| armhf | ELF32 | ARM | /lib/ld-linux-armhf.so.3 | Loads on a soft-float system, then fails on a float ABI call |
| i386 | ELF32 | Intel 80386 | /lib/ld-linux.so.2 | Exec format error where no 32-bit loader package exists |
各行は、語長が正しく見えるのにコードが誤動作する事例か、起動してから一層下で失敗する事例です。インタープリターの列は、カーネルがあなたのコードのどれかが動く前にそのパスを解決するため、ヒントではなく厳格な要件として読んでください。エミュレーションは独自の性能とサポートの影響を伴う配備上の判断であり、より広い語長を宣伝するプロセッサが暗に示すものではありません。
dpkg --print-architecture
ENOEXEC と ENOENT は別の失敗です
起動段階は二つのエラーのどちらかを報告し、それぞれ別の問題を指します。エラー値を読むことで、他の何かを動かす前に失敗を分類できます。
ENOEXEC は、アーキテクチャが違う、クラスが違う、あるいは実行ファイルでない何かという形で形式が認識されなかったことを意味します。ELF ファイルでの ENOENT は通常、要求したファイルが存在していてもインタープリターが欠けていることを意味します。同じ ENOENT はスクリプトのインタープリター不在を意味することもあり、だからスクリプトの一行目が重要です。いずれにせよメッセージは層を名指ししており、すべての「見つからない」を設定不足として扱うと調査は誤った方向へ進みます。チケットには、周囲の文よりも再説明に耐えるため、エラー値を引用してください。
バイナリが起動しないときにしないこと
説明のつかないバイナリをシェルラッパーで強引に通しても動きません。信頼していないファイルに対しては、状況によってはバイナリ内のコードを実行してしまうことがあるため、依存関係チェッカーを気軽に実行しないでください。ローダーのシンボリックリンクを足したり、ホストのライブラリを差し替えたり、メッセージを避けるために第三者ミラーから古いアーカイブを取ってきたりしないでください。どれもヘッダーがすでに名指した不一致に触れないまま、変更の範囲を広げるだけです。
ベンダーに連絡するときは、物語ではなく、OS のリリース、パッケージのアーキテクチャ、クラスとマシンの文字列、要求したインタープリター、最初のエラー行という値を送ってください。その組は、失敗するインストーラーのスクリーンショットより速くサポートの問いを解決します。古い成果物や記憶のフォーラム出力は現在のサポートマトリクスではなく、ネイティブのバイナリが読み込まれた後も、プロファイル、認証、ルーティングは別の作業として残ります。