Huny's Dev Blog
huny.dev

Linux ELF Binary Exists but Returns ENOENT? Check PT_INTERP

Diagnose ENOENT for an executable ELF file with readelf, verify its dynamic loader path, and match the build and runtime environments.

Hun Jang
Hun Jang Nov 13, 2026

If a Linux ELF binary exists and has execute permission but reports No such file or directory, run readelf -lW ./app and check the program interpreter path. When the loader required by a dynamically linked ELF is absent from the runtime environment, the kernel can return ENOENT even though the executable exists. A local example shows how to diagnose this after moving a binary to a container or another distribution.

A cyan executable module beside an empty slot outlined in amber

Why the kernel can return ENOENT for an existing file

A dynamically linked ELF records the interpreter path in its PT_INTERP program header. The kernel opens the loader at that path during execution. execve(2) can return ENOENT when the executable path is absent, or when the ELF interpreter or script interpreter is absent. If the error persists after checking the path and execute permission, inspect the interpreter the binary requests. Linux execve(2) · ELF format

Inspect the loader path and architecture

  1. Check Machine in readelf -hW ./app. Compare it with the intended target architecture. If it differs from the host, check that the runtime has the appropriate emulation configured.
  1. Find INTERP and Requesting program interpreter in readelf -lW ./app. Check that the absolute path is valid in the actual runtime. For a container, check the final image’s filesystem and follow any symlink to its target.
  1. If the loader is present and the error names a shared library, inspect the NEEDED entries from readelf -dW ./app and the loader’s search paths. NEEDED lists the binary’s direct dependencies, so check any further dependencies required by those libraries separately. GNU readelf documentation · Linux ld.so(8)

Reproduce ENOENT with an existing executable

The example builds two binaries from the same C source. It uses a GNU linker option to give the second binary a loader path that does not exist in the temporary directory. On Linux with Python 3, GCC, the GNU linker, and readelf, save it as elf_loader_demo.py and run python3 elf_loader_demo.py. GNU ld options

The example ran on Linux x86-64 with Python 3.12.14, GCC 14.2.0, and GNU Binutils 2.44 on November 13, 2026. The first binary printed successfully. The second failed with ENOENT even though the file existed and had execute permission.

Match the build and runtime environments

For deployment, choose a runtime that matches the architecture and libc family used to build the binary, and include the required shared libraries. When moving a glibc binary to a musl-based image, rebuild for the target or choose a compatible runtime. Matching the loader filename alone can still leave incompatible libc or shared library ABIs. For programs that support static linking, consider a static build and verify whether it has PT_INTERP and whether it runs as expected. Linux ld.so(8) · ELF format

The example verifies the missing ELF loader case locally. Containers, static builds, and execution on other architectures were outside the test scope.

한국어 버전 · Linux ELF 실행 파일이 있는데 ENOENT가 날 때 PT_INTERP 확인하기Linux ELF 실행 파일이 있는데 ENOENT가 날 때 PT_INTERP 확인하기

추천 글