何が起きたのか
バイナリをダウンロードしたり、プログラムをコンパイルしたり、別のマシンから実行ファイルをコピーしたりして、実行したところ以下のエラーが表示された:
bash: ./app: cannot execute binary file: Exec format error
シェルはファイルを見つけ、実行ビットが設定されていることも確認した。しかしカーネルは実行を完全に拒否した。この拒否はほぼ必ず3つのいずれかが原因だ:バイナリが異なるCPUアーキテクチャ向けである、ファイルが実際には実行ファイルではない、またはELFインタープリタが存在しない。原因ごとに異なる対処が必要となる。診断を省略すると、間違った方法に20分を費やすことになる。
ステップ1 — ファイルの実体を確認する
バイナリに対して file コマンドを実行する。どのアーキテクチャおよびフォーマット向けにビルドされているかを最速で確認できる方法だ:
file ./app
出力例とその意味:
# x86_64マシン上のARMバイナリ — アーキテクチャの不一致
./app: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
# x86_64バイナリ — 最新のLinuxマシンの多くで動作するはず
./app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV)
# ELFではない — 誰かがリネームしたWindowsの.exeかもしれない
./app: PE32+ executable (console) x86-64, for MS Windows
# シェバンのないシェルスクリプト
./app: ASCII text
自分のマシンのアーキテクチャを確認する:
uname -m
# x86_64 → Intel/AMD 64ビット
# aarch64 → ARM 64ビット(Apple Silicon、Raspberry Pi 4、AWS Graviton)
# armv7l → ARM 32ビット(旧型Raspberry Pi)
file の出力と uname -m が一致しない場合、それが原因だ。
ステップ2 — 正確な原因を特定する
原因A:アーキテクチャの不一致(最も一般的)
x86_64マシン上でARMバイナリを実行しているか、またはその逆のケースだ。以下の4つの状況が確実にこれを引き起こす:
- アーキテクチャのラベルを確認せずにインターネットからビルド済みバイナリを取得した
- Apple Silicon Mac(aarch64)でビルドし、x86_64サーバーにバイナリをコピーした
- ホストとは異なるアーキテクチャをターゲットにしたベースイメージのDockerコンテナ内にいる
- クロスコンパイルしたが、ターゲットを正しく設定しなかった
原因B:ファイル形式の誤り(ELFではない)
WindowsのPE実行ファイル(.exe)、macOSのMach-Oバイナリ、シェバン行のないプレーンテキストスクリプトはすべて同じエラーを生成する。ファイルの拡張子は関係ない — Linuxは名前ではなくマジックバイトを使用する。
原因C:32ビットライブラリなしの64ビットシステム上の32ビットバイナリ
アーキテクチャが一致するバイナリでもここで失敗することがある。64ビットLinuxシステム上の32ビットx86 ELFは lib32 パッケージのインストールが必要だ:
file ./app
# ./app: ELF 32-bit LSB executable, Intel 80386
ステップ3 — 適切な修正を適用する
修正A:自分のアーキテクチャに合った正しいバイナリを入手する
ビルド済みリリースをダウンロードする場合は、プラットフォームに合った適切なアーカイブを選ぶ。多くのプロジェクトでは予測可能な命名規則を使用している:
# x86_64 / amd64
app-linux-amd64
app-linux-x86_64
# ARM 64ビット
app-linux-arm64
app-linux-aarch64
# ARM 32ビット
app-linux-armv7
app-linux-arm
ダウンロードし、file で確認してから実行する:
curl -LO https://example.com/releases/app-linux-amd64
chmod +x app-linux-amd64
file ./app-linux-amd64
./app-linux-amd64
修正B:ターゲットアーキテクチャ向けに再コンパイルする
ソースコードがあるなら、ターゲットマシン上で直接コンパイルするか、適切なターゲットフラグを指定してクロスコンパイルする。
Goはクロスコンパイルを非常に簡単にしている — 必要なのは2つの環境変数だけだ:
# Linux x86_64向けにコンパイル
GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
# Linux ARM64向けにコンパイル
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
GCCを使ったCの場合は、まずクロスコンパイラのツールチェーンをインストールする:
# ARMクロスコンパイラをインストール
sudo apt install gcc-aarch64-linux-gnu
# ARM64向けにコンパイル
aarch64-linux-gnu-gcc -o app-arm64 main.c
修正C:QEMUエミュレーションを追加する(再コンパイルなしで異種アーキテクチャのバイナリを実行)
再コンパイルできない場合もある — バイナリがクローズドソースだったり、簡単なテストだけが必要だったりする場合だ。QEMUユーザーモードエミュレーションを使えば、ソースに触れることなく異種アーキテクチャのバイナリを実行できる:
# QEMUユーザーモードエミュレーションをインストール
sudo apt install qemu-user qemu-user-static
# x86_64上でARM64バイナリを実行
qemu-aarch64 ./app-arm64
# カーネルがQEMUを自動的に呼び出すようbinfmt_miscハンドラを登録
sudo apt install binfmt-support
sudo update-binfmts --enable qemu-aarch64
binfmtハンドラが登録されると、プレフィックスが不要になる:
./app-arm64 # QEMUを経由して透過的に実行される
修正D:32ビットELFバイナリのために32ビットサポートをインストールする
# Debian/Ubuntu
sudo apt install lib32z1 lib32stdc++6
# CentOS/RHEL
sudo yum install glibc.i686 libstdc++.i686
修正E:スクリプトの場合はシェバンを追加する
file がプレーンテキストを出力する場合、そのファイルにはインタープリタ行が欠けている。最初の行を確認する:
head -1 ./app
先頭に #! がない場合は追加する:
#!/usr/bin/env bash
# スクリプトの残り...
その後、実行ビットを再設定して実行する:
chmod +x ./app
./app
Docker特有のシナリオ
Dockerコンテナはこのエラーが最も人を驚かせる場所だ。x86_64 ホスト上で arm64 イメージを取得したり、M1 MacでビルドしてクラウドVMにデプロイしたりすると、気づかないうちに誤ったアーキテクチャが生成される。リリース前に確認しよう:
# イメージのアーキテクチャを確認
docker inspect --format='{{.Architecture}}' myimage
# 特定のプラットフォームを明示的に取得
docker pull --platform linux/amd64 myimage
# 特定のプラットフォーム向けにビルド
docker buildx build --platform linux/amd64 -t myimage .
AWS GravitonやRaspberry PiなどのARMサーバーにデプロイする場合は、ビルドステップで --platform linux/arm64 を設定し、後付けではなくCIパイプラインの一部として組み込もう。
修正が有効かどうかを確認する
# 1. アーキテクチャが自分のマシンと一致することを確認
file ./app
uname -m
# 2. バイナリを実行
./app
# 3. 終了コードを確認 — 0は成功を意味する
echo $?
アーキテクチャを修正してもまだ失敗する場合は、不足している共有ライブラリが次の容疑者だ:
ldd ./app
# 以下のような行を探す:
# libssl.so.1.1 => not found
not found の各エントリは、インストールが必要なパッケージに対応している。
クイックリファレンス
- アーキテクチャの不一致 → ターゲットアーキテクチャ向けの正しいバイナリをダウンロードするか再コンパイルする
- 異種アーキテクチャのバイナリを実行する必要がある → QEMUユーザーモード + binfmt_miscをインストールする
- 64ビットシステム上の32ビットバイナリ →
lib32パッケージをインストールする - シェバンのないスクリプト → 最初の行に
#!/usr/bin/env bashを追加する - Windows/macOSのバイナリ → Linuxビルドが必要、それ以外の方法はない
まず file ./app を実行しよう。常に。2秒の出力が、上記5つの修正のどれが適用されるかを正確に教えてくれる。

