Case 128: Symbol Binding Strengthened (Weak → Global)¶
| Field | Value |
|---|---|
| Verdict | 🟢 COMPATIBLE |
| Category | Quality (Compatible) |
| Platforms | Linux |
| Flags | — |
Detected ChangeKinds |
symbol_binding_strengthened |
| Source files | examples/case128_symbol_binding_strengthened/ |
Category: Symbol Binding | Verdict: 🟢 COMPATIBLE
Verdict and consumer impact¶
The exported function helper is defined with weak binding (STB_WEAK) in
v1 and strong/global binding (STB_GLOBAL) in v2. Every binary that
previously resolved calls to the weak helper resolves to the same
definition in v2 — the address and behavior are unchanged, so no consumer
needs to recompile or is otherwise affected. The only semantic difference is
that a strong symbol can no longer be silently overridden by another strong
definition elsewhere in the link — that removes a footgun (accidental
interposition), it does not break callers.
Old/new diff¶
| v1.c | v2.c |
|---|---|
__attribute__((weak)) int helper(int x) { ... } |
int helper(int x) { ... } |
STB_WEAK |
STB_GLOBAL |
abicheck command¶
gcc -shared -fPIC -g v1.c -o libbind_v1.so
gcc -shared -fPIC -g v2.c -o libbind_v2.so
abicheck compare libbind_v1.so libbind_v2.so
Expected abicheck finding¶
Verdict: COMPATIBLE (exit 0)
Quality Issues:
- symbol_binding_strengthened: Symbol binding changed: helper (weak -> global)
Minimum evidence¶
min_evidence: L0 — a symbol's binding (STB_WEAK/STB_GLOBAL) is a field
in the ELF symbol table itself; no debug info or headers are required.
Why abicheck catches it¶
abicheck reads each exported symbol's st_info binding field from both
binaries' .dynsym and reports a flip. Weak→strong is classified compatible
(quality-improvement) rather than risky, since it can only remove
overridability, never change which definition existing callers reach.
Runtime failure demonstration¶
No observable effect on existing binaries. The strengthened symbol resolves to the identical implementation either way, so there is no failure to demonstrate — swapping the library binary is silent.
# Build old library + app
gcc -shared -fPIC -g v1.c -o libbind.so
gcc -g app.c -I. -L. -lbind -Wl,-rpath,. -o app
./app
# -> result = 16
# Swap in new library (no recompile)
gcc -shared -fPIC -g v2.c -o libbind.so
./app
# -> result = 16 (identical -- weak->strong is backward compatible)
Safe redesign¶
This case is the safe practice — weak→strong is the direction to prefer once a symbol is no longer meant to be interposable. The reverse direction (strong→weak) is the risky one: a previously guaranteed definition could afterwards be silently overridden or left unresolved (see case27, its risky counterpart). Keep public API symbols strong by default, and reserve weak binding for intentional fallback/override hooks, documented as such.
Cross-tool comparison¶
abidiff also reads ELF symbol-table binding and would report the same
weak→strong transition — this is a pure L0 fact both tools read from the
same field.
Source files¶
CMakeLists.txtapp.cv1.cv1.hv2.cv2.h
See also: Examples overview · All COMPATIBLE cases · Category: Quality (Compatible).