Case 138: DT_NEEDED Added¶
| Field | Value |
|---|---|
| Verdict | ๐ข COMPATIBLE |
| Category | Quality (Compatible) |
| Platforms | Linux |
| Flags | โ |
Detected ChangeKinds |
needed_added |
| Source files | examples/case138_needed_added/ |
Category: Quality | Verdict: ๐ข COMPATIBLE
Verdict and consumer impact¶
v2's exported symbols and their types are unchanged, so binaries already
linked against libfoo keep working exactly as before. What changes is the
library's own runtime dependency closure: v2 is linked with
-Wl,--no-as-needed -lm, so it now carries a DT_NEEDED entry for
libm.so.6 even though it calls no math function. This is invisible to
existing consumers, but it matters for packaging (an extra Requires:),
container image size, and any deployment where libm might not be present.
Old/new diff¶
| old/lib.c | new/lib.c |
|---|---|
int compute(int x) { return x * x + 1; } |
int compute(int x) { return x * x + 1; } |
int transform(int x, int y) { return x + y * 2; } |
int transform(int x, int y) { return x + y * 2; } |
| (linked normally) | (linked with -Wl,--no-as-needed -lm) |
abicheck command¶
gcc -shared -fPIC -g old/lib.c -o libfoo_v1.so
gcc -shared -fPIC -g new/lib.c -o libfoo_v2.so -Wl,--no-as-needed -lm
abicheck compare libfoo_v1.so libfoo_v2.so
Expected abicheck finding¶
Verdict: COMPATIBLE (exit 0)
Quality Issues:
- needed_added: New dependency added: libc.so.6
- needed_added: New dependency added: libm.so.6
- symbol_version_required_added_compat: New symbol version requirement:
GLIBC_2.2.5 (from libc.so.6) โ not newer than previous max, backward-compatible
Minimum evidence¶
min_evidence: L0 โ the .dynamic section's DT_NEEDED entries are read
straight from the ELF headers; no debug info or public headers needed.
Why abicheck catches it¶
abicheck parses the .dynamic section of both binaries and diffs the sets
of DT_NEEDED entries directly; a name present in v2 but absent from v1 is
reported as needed_added regardless of whether any symbol from that
dependency is actually called.
Runtime failure demonstration¶
Severity: INFORMATIONAL โ no observable effect on existing binaries.
# Build old library + app
gcc -shared -fPIC -g old/lib.c -o libfoo.so
gcc -g app.c -L. -lfoo -Wl,-rpath,. -o app
./app
# โ compute(7) = 50
# โ transform(3, 4) = 11
# Swap in new library (no recompile)
gcc -shared -fPIC -g new/lib.c -o libfoo.so -Wl,--no-as-needed -lm
./app
# โ compute(7) = 50
# โ transform(3, 4) = 11 (identical โ libm is present on this host)
The added DT_NEEDED only causes a failure on a system where libm.so.6
is unavailable at load time (error while loading shared libraries); on
any host with a normal glibc/libm install, behavior is identical.
Safe redesign¶
Link with --as-needed (the default on most modern toolchains) so only
libraries whose symbols are actually referenced become DT_NEEDED. If a
dependency is intentionally required for future use, add it deliberately
and document it rather than picking it up as a side effect of link-flag
ordering.
Real-world example: distro packaging tools (e.g. rpmbuild's
auto-Requires generator) derive a package's runtime dependencies from
DT_NEEDED entries โ a stray added DT_NEEDED silently widens the
package's dependency closure and its container/image footprint.
Cross-tool comparison¶
readelf -dW libfoo_v1.so | grep NEEDED
readelf -dW libfoo_v2.so | grep NEEDED # adds libm.so.6, libc.so.6
Source files¶
CMakeLists.txtapp.c
See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).