Выберите продукт

Debian/Ubuntu: как исправить exec format error и bad ELF interpreter

В Debian и Ubuntu ошибки exec format error, bad ELF interpreter и cannot execute binary file обычно связаны не с правами, а с несовместимой архитектурой, битностью, libc или отсутствующим dynamic linker. Разберём быстрый алгоритм диагностики ELF-бинарников, 32-битных приложений и контейнеров Docker.
Debian/Ubuntu: как исправить exec format error и bad ELF interpreter

Ошибки exec format error, bad ELF interpreter и cannot execute binary file в Debian и Ubuntu выглядят тревожно, но в большинстве случаев сводятся к нескольким типовым причинам. Чаще всего это запуск бинарника не той архитектуры, например сборки под arm64 на хосте amd64, или наоборот. На втором месте — отсутствие нужного динамического загрузчика, когда ELF-файл формально подходит, но система не может найти требуемый интерпретатор.

Отдельный класс проблем возникает в контейнерах: образ собран под одну платформу, а запускается на другой. Ещё одна частая история — перенос бинарника между Alpine и Debian/Ubuntu без учёта различий между musl и glibc. Внешне симптомы похожи, но исправление у каждого случая своё.

Хорошая новость в том, что такие сбои диагностируются быстро, если не гадать, а идти по шагам: определить архитектуру хоста, посмотреть, что именно представляет собой файл, проверить путь к dynamic linker и только потом разбираться с библиотеками, Docker или shebang.

Что означают эти ошибки

Формулировки похожи, но смысл у них немного разный.

  • cannot execute binary file — оболочка не может запустить файл как исполняемый бинарник. Часто это неверная архитектура, повреждённый файл или попытка выполнить текстовый файл как бинарный.
  • exec format error — ядро не распознало формат исполняемого файла для текущей среды. Классический случай: бинарник собран под другую CPU-архитектуру.
  • bad ELF interpreter — ELF-файл распознан, но указанный внутри интерпретатор отсутствует по нужному пути.

Проще говоря, первые две ошибки чаще говорят: «это не тот бинарник для этой машины», а третья — «бинарник подходит, но не хватает runtime-компонента для старта».

Если нужен быстрый порядок проверки: сначала архитектура ELF, затем битность, затем путь к dynamic linker и только после этого зависимости и контейнерное окружение.

Быстрый чек-лист диагностики

Когда вы видите такую ошибку, не стоит сразу ставить пакеты наугад. Сначала соберите базовые факты о системе и файле.

uname -m
getconf LONG_BIT
file ./mybin
readelf -h ./mybin
readelf -l ./mybin | grep 'interpreter'
ldd ./mybin

Этого набора обычно достаточно для первичной диагностики:

  • uname -m показывает архитектуру хоста, например x86_64 или aarch64.
  • getconf LONG_BIT быстро показывает 32- или 64-битную среду.
  • file определяет формат ELF, архитектуру и тип линковки.
  • readelf -h показывает заголовок ELF: класс, machine type и ABI.
  • readelf -l позволяет увидеть ожидаемый интерпретатор.
  • ldd помогает понять, каких библиотек не хватает, если файл вообще удаётся разобрать.

Дополнительно полезно посмотреть код возврата и сообщения ядра:

./mybin
echo $?
dmesg | tail -n 20

Если вы часто разворачиваете приложения в изолированной среде, на практике удобнее сразу иметь отдельный сервер или стенд на VDS, где можно быстро сверить архитектуру, libc и поведение контейнеров без влияния соседних сервисов.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Сценарий №1: неправильная архитектура — amd64 против arm64

Это самый частый случай. Бинарник выглядит нормальным, права на исполнение стоят, но Debian или Ubuntu отвечает cannot execute binary file либо exec format error. Обычно это значит, что файл собран не под ту архитектуру.

Типичный пример: сервер работает на amd64, а вы скачали релиз для arm64. Или локально сборка сделана на ARM-машине, а деплой идёт на обычный x86_64-хост. Особенно часто это всплывает в CI и Docker.

Как проверить архитектуру системы

uname -m
dpkg --print-architecture
lscpu | grep Architecture

Полезно помнить типичные соответствия:

  • x86_64 и amd64 — одна и та же 64-битная архитектура x86.
  • aarch64 и arm64 — одна и та же 64-битная ARM-архитектура.
  • i386 и i686 — 32-битный x86.
  • armhf и armv7 — 32-битный ARM.

Как проверить архитектуру бинарника

file ./mybin
readelf -h ./mybin | grep -E 'Class|Machine'

Если хост показывает x86_64, а file сообщает, что это ELF для ARM aarch64, причина найдена. Такой файл нативно не запустится.

Исправление простое: скачать корректную сборку или пересобрать приложение под нужную платформу. Если вы работаете со смешанной инфраструктурой, полезно держать отдельные артефакты и не полагаться только на имя архива. Для серверов на ARM может пригодиться и статья про сценарии, где ARM VDS действительно выгоден для PHP и Node.js.

Проверка архитектуры ELF-файла командами file и readelf

Сценарий №2: 32-битный бинарник на 64-битной системе

64-битная Debian или Ubuntu не всегда автоматически запускает старые 32-битные приложения. Это возможно только при наличии нужных 32-битных runtime-компонентов. Когда их нет, нередко появляется именно bad ELF interpreter.

Классический симптом: бинарник определяется как 32-битный ELF для Intel 80386, а система жалуется на отсутствие /lib/ld-linux.so.2 или похожего загрузчика.

Как увидеть, какой linker нужен

readelf -l ./legacy-app | grep interpreter
file ./legacy-app

Если в выводе фигурирует /lib/ld-linux.so.2, приложению нужен 32-битный загрузчик glibc. На чистом x86_64-хосте его может не быть.

Как включить multiarch и поставить нужные пакеты

sudo dpkg --add-architecture i386
sudo apt update
sudo apt install libc6:i386 libstdc++6:i386

После установки снова проверьте зависимости:

ldd ./legacy-app

Если ldd показывает not found, ставьте недостающие библиотеки точечно. Так проще поддерживать систему и понимать, что именно нужно приложению.

Сценарий №3: бинарник собран под musl, а система ждёт glibc

Иногда архитектура совпадает, но проблема не в CPU, а в libc. Например, вы берёте исполняемый файл из Alpine и пытаетесь запустить его в Debian или Ubuntu. Формально ELF может быть правильной архитектуры, но путь к интерпретатору и ABI будут другими.

Для Debian/Ubuntu обычно ожидается glibc-loader вида /lib64/ld-linux-x86-64.so.2 на x86_64. Для Alpine часто используется musl, и интерпретатор будет другим. В итоге система пишет, что файл не запускается или отсутствует interpreter.

Как распознать проблему libc

file ./mybin
readelf -l ./mybin | grep interpreter
strings ./mybin | grep -Ei 'glibc|musl' | head

В такой ситуации надёжнее пересобрать приложение под целевую систему, чем пытаться вручную совмещать чужие рантаймы. Особенно это важно для production-окружений.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Сценарий №4: проблема не в ELF, а в shebang

Иногда сообщение cannot execute binary file сбивает с толку, хотя файл вообще не бинарный. Это может быть скрипт с неправильной первой строкой: указан несуществующий интерпретатор, либо файл сохранён с Windows-окончаниями строк.

Сначала проверьте, что вы вообще запускаете:

file ./runme
head -n 1 ./runme
sed -n '1,3p' ./runme

Если там указан #!/bin/bash, а в контейнере есть только /bin/sh, запуск закончится ошибкой. Если shebang содержит скрытый \r, система будет искать несуществующий путь.

Проверить это можно так:

sed -n '1p' ./runme | cat -vet

Если в конце строки виден ^M, переведите файл в Unix-формат:

sed -i 's/\r$//' ./runme

Сценарий №5: Docker-образ собран не под ту платформу

В Docker проблема встречается особенно часто. Образ может успешно скачаться, но на старте контейнера вы получите exec format error, потому что entrypoint или базовый слой рассчитан на другую архитектуру.

Типовой сценарий: образ собран на ARM-ноутбуке, затем публикуется и запускается на Debian/Ubuntu-сервере с amd64. Внешне Dockerfile может быть корректным, но платформа артефакта не совпадает с платформой хоста.

Что проверить в Docker

docker image inspect myimage --format '{{.Architecture}} {{.Os}}'
docker inspect mycontainer --format '{{.Platform}}'
uname -m

Если архитектура образа не совпадает с архитектурой сервера, причина очевидна. Для multi-platform-сборок лучше явно задавать платформу на этапе сборки:

docker buildx build --platform linux/amd64 -t myimage:amd64 .
docker buildx build --platform linux/arm64 -t myimage:arm64 .

Для быстрой проверки гипотезы можно явно указать платформу и при запуске:

docker run --platform linux/amd64 --rm myimage:latest

Но это не универсальное решение: без поддержки эмуляции или без корректного multi-arch-образа контейнер всё равно не заработает. Если вы дополнительно разбираете сетевые проблемы контейнеров, полезно держать под рукой разбор взаимодействия Docker с iptables и nftables, потому что часть симптомов на старте контейнера админы ошибочно принимают за проблемы сети, а не платформы.

Ошибка запуска Docker-контейнера из-за несовпадения платформы образа и хоста

Как читать ELF без гадания

Команды file часто достаточно, но в спорных случаях полезно понимать, что именно смотреть в ELF-заголовке.

  • Class — 32- или 64-битный формат.
  • Machine — архитектура процессора.
  • OS/ABI — ABI-совместимость.
  • interpreter в program headers — путь к dynamic linker.
readelf -h ./mybin
readelf -l ./mybin

Если Machine не совпадает с хостом, это почти наверняка неправильная архитектура. Если совпадает, но нужный interpreter отсутствует, перед вами сценарий с bad ELF interpreter. Если бинарник статический, секции с интерпретатором может не быть вовсе.

Что делать, если файл повреждён или скачан не полностью

Хотя это более редкий сценарий, повреждённый файл тоже может давать ошибки формата. Артефакт мог обрезаться в CI, скачаться не полностью, распаковаться с ошибкой или вообще оказаться HTML-страницей вместо бинарника.

file ./mybin
sha256sum ./mybin
ls -lh ./mybin

Если file показывает HTML document или ASCII text там, где вы ждёте ELF, значит проблема вообще не в интерпретаторе, а в источнике артефакта.

Пошаговый runbook для Debian/Ubuntu

Если нужен короткий рабочий алгоритм, используйте такой порядок:

  1. Проверьте архитектуру хоста через uname -m и dpkg --print-architecture.
  2. Проверьте файл через file и readelf -h.
  3. Если архитектура не совпадает, скачайте или пересоберите правильный бинарник.
  4. Если архитектура совпадает, посмотрите readelf -l и найдите interpreter.
  5. При отсутствии loader установите нужные runtime-пакеты и при необходимости включите multiarch.
  6. Если это контейнер, сравните платформу хоста, образа и entrypoint.
  7. Если это скрипт, проверьте shebang и окончания строк.
  8. Если картина не сходится, проверьте целостность файла и источник сборки.

Типичные примеры и их смысл

Пример 1: x86_64-сервер, ARM-бинарник

$ uname -m
x86_64

$ file ./app
./app: ELF 64-bit LSB pie executable, ARM aarch64, dynamically linked

$ ./app
bash: ./app: cannot execute binary file: Exec format error

Здесь всё просто: бинарник для arm64, а система — amd64.

Пример 2: 32-битное приложение на Ubuntu amd64

$ file ./legacy-app
./legacy-app: ELF 32-bit LSB executable, Intel 80386, dynamically linked

$ ./legacy-app
bash: ./legacy-app: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory

Здесь не хватает 32-битного загрузчика и, вероятно, библиотек i386.

Пример 3: Docker-образ другой платформы

$ docker image inspect myimage --format '{{.Architecture}}'
arm64

$ uname -m
x86_64

$ docker run --rm myimage
exec /usr/local/bin/app: exec format error

Проблема не в коде приложения, а в несовпадении платформы образа и хоста.

Как предотвратить проблему в CI/CD

Лучшее решение — не искать причину уже после деплоя, а проверять артефакты заранее.

  • Проверяйте итоговый бинарник через file.
  • Явно маркируйте артефакты архитектурой в имени файла.
  • Для Docker используйте multi-arch manifests и явный --platform.
  • Тестируйте запуск entrypoint в целевой среде.
  • Не переносите бинарники из Alpine в Debian/Ubuntu без понимания различий в libc.

Итог

Ошибки exec format error, bad ELF interpreter и cannot execute binary file в Debian/Ubuntu почти всегда имеют конкретную и проверяемую причину. Обычно это либо неверная архитектура, либо отсутствующий dynamic linker, либо несовпадение платформы в Docker.

Главное правило простое: не лечите вслепую. Сначала проверьте архитектуру хоста, затем формат ELF, потом интерпретатор и зависимости. Такой порядок почти всегда приводит к точному ответу за несколько минут.

Если у вас несколько сред и смешанные платформы, имеет смысл встроить эти проверки в CI/CD и runbook дежурной команды. Тогда проблема обнаружится до выката, а не ночью после релиза.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: как исправить Permission denied (publickey) из-за ~/.ssh, authorized_keys и прав на home directory OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Permission denied (publickey) из-за ~/.ssh, authorized_keys и прав на home directory

Если SSH-ключи в Debian или Ubuntu перестали работать и сервер отвечает Permission denied (publickey), причина часто не в ключе, а ...
Debian/Ubuntu: как устранить ARP flux при нескольких IP на одном сервере OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как устранить ARP flux при нескольких IP на одном сервере

Если на Debian или Ubuntu сервере несколько IP-адресов, можно столкнуться с ARP flux: хост отвечает на ARP-запросы не тем интерфей ...
Debian/Ubuntu: как исправить inotify limits, max_user_watches и Too many open files OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить inotify limits, max_user_watches и Too many open files

Если webpack, Vite, VS Code, systemd path units или CI runner перестают следить за файлами в Debian/Ubuntu, причина часто в лимита ...