Short answer
ldd reads the dynamic section of an ELF file. A statically linked binary has none,
so ldd reports not a dynamic executable and exits 1. The binary is not broken.
It simply does not need a loader at runtime.
This is the most common false alarm in Linux binary troubleshooting: people read it as
"the executable is invalid" and start looking for a missing library that does not exist.
Confirm it in three commands
Take any static binary — a Go or Rust build, or busybox from a static image — and run:
$ ldd ./hello-static
not a dynamic executable
$ echo $?
1
$ file ./hello-static
./hello-static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
statically linked, Go BuildID=rLXBd7VvG-TozsbigJ3a/..., stripped
$ readelf -d ./hello-static
There is no dynamic section in this file.
file says statically linked and readelf -d says no dynamic section. Both agree
with ldd. Nothing is missing.
What the message actually means
| Tool | Says | Because |
|---|---|---|
ldd |
not a dynamic executable |
no DT_NEEDED, no PT_INTERP
|
file |
statically linked |
same reason, different wording |
readelf -d |
There is no dynamic section in this file. |
the .dynamic section is absent |
| `readelf -l \ | grep -c INTERP` | 0 |
Contrast with a dynamically linked binary on the same host:
$ readelf -l ./hello-new | grep -A1 INTERP
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
$ readelf -d ./hello-new | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
An INTERP entry plus a list of NEEDED libraries is what ldd needs to do its job.
A static binary has neither.
Where this shows up in practice
Go and Rust builds. CGO_ENABLED=0 Go builds and musl-targeted Rust builds are static
by default. Running ldd on them is a category error, not a defect.
Distroless and scratch images. There is no shell, no binutils, sometimes no ldd.
Static busybox. busybox --install links applets into a single static binary; every
applet reports this message.
Jump hosts without binutils. A slim debian:12 image has neither file nor readelf:
$ file ./hello-static
sh: 1: file: not found
$ readelf -h ./hello-static
sh: 1: readelf: not found
That is exactly the situation the ELF Inspector exists for — it
parses in your browser, so the target host needs no tooling and the binary is not uploaded.
When not a dynamic executable is a real problem
Rarely, but it matters:
-
You expected a dynamic binary. If a build system silently produced a static binary,
dlopen()will fail at runtime because there is no dynamic loader in the process. -
glibc NSS breaks. A fully static glibc binary cannot load NSS modules
(
getpwnam, DNS viagetaddrinfocan behave oddly). Use-staticwith care, or prefer static musl. -
The binary was corrupted mid-transfer. Combined with a truncated file,
lddcan also report this. Check the size and a checksum if the file came over the network.
In every other case the message is informational.
What to use instead
# what kind of file is it at all
file ./binary
# architecture, word size, endianness, type
readelf -h ./binary | head -20
# any dynamic dependencies (empty output = static)
readelf -d ./binary | grep NEEDED
# interpreter present?
readelf -l ./binary | grep INTERP
# the same information without installing binutils
# -> open the binary in the browser ELF Inspector
The browser tool reports the same fields and adds the verdicts that are easy to get wrong
by hand: PIE, static vs shared object, full RELRO, stripped, and the required
GLIBC_* / GLIBCXX_* symbol versions.
One safety note about ldd
For dynamically linked binaries, ldd is not a pure reader. Most implementations
execute the program's own loader (LD_TRACE_LOADED_OBJECTS) to get the resolution result.
On an untrusted binary that means running its interpreter.
Static binaries are not affected — that is the one case where ldd genuinely cannot
execute anything. For untrusted files, prefer readelf -d or the browser tool, which only
parse data.
FAQ
Does not a dynamic executable mean the binary is corrupted? No. It means there is no
dynamic section to inspect. A corrupted file usually gives a different error
(cannot execute binary file, invalid ELF header).
Why does ldd exit 1 then? Because it could not perform the requested inspection.
Exit status reflects the tool's success, not the binary's validity.
How do I know whether a binary is static or dynamic without ldd? file prints
statically linked or dynamically linked; readelf -d prints the dynamic section or
says there is none.
Can a static binary still fail at runtime? Yes — on a kernel that does not support its
architecture, on a filesystem mounted noexec, or when it needs files it expects to find
(glibc static + NSS). Those are different errors than this one.
Top comments (0)