Case 27 โ Symbol Binding Weakened (GLOBAL โ WEAK)¶
| Field | Value |
|---|---|
| Verdict | ๐ข COMPATIBLE |
| Category | Quality (Compatible) |
| Platforms | Linux |
| Flags | โ |
Detected ChangeKinds |
โ |
| Source files | browse on GitHub |
Verdict: ๐ข COMPATIBLE abicheck verdict: COMPATIBLE (informational/warning)
What changes¶
| Version | ELF binding |
|---|---|
| v1 | foo: GLOBAL DEFAULT |
| v2 | foo: WEAK DEFAULT |
This typically happens when a library applies __attribute__((weak)) to a previously
strong (GLOBAL) symbol, or when a linker script changes binding.
Why this is NOT a binary ABI break¶
A WEAK symbol is still exported and resolvable by the dynamic linker. Existing
binaries that linked against the GLOBAL version of foo will find and use the
(now WEAK) symbol without any change in behavior.
abicheck classifies this as COMPATIBLE because:
- The symbol is still present in .dynsym and resolvable.
- No calling convention, type layout, or signature change occurs.
- The dynamic linker resolves WEAK symbols the same way as GLOBAL when no
override is present.
What it does affect¶
- Symbol interposition: a WEAK symbol can be overridden by a GLOBAL definition from another shared object or the main executable. If the consumer's environment provides an alternative definition, the WEAK version may not be used.
- Linker behavior: some linkers treat WEAK symbols differently during static linking (e.g., not pulling the object file from an archive).
These are deployment/interposition concerns, not binary compatibility failures.
Contrast with BREAKING binding changes¶
The reverse direction โ WEAK โ GLOBAL (SYMBOL_BINDING_STRENGTHENED) โ is also
classified as COMPATIBLE. Neither direction breaks existing symbol resolution.
Code diff¶
/* v1: normal definition */
-int foo(void) { return 42; }
+__attribute__((weak)) int foo(void) { return 42; }
Real Failure Demo¶
Severity: INFORMATIONAL
Scenario: app calls foo(). Both GLOBAL and WEAK versions return 42 โ no runtime difference.
# Build old lib (GLOBAL foo) + app
gcc -shared -fPIC -g old/lib.c -Iold -o libfoo.so
gcc -g app.c -Iold -L. -lfoo -Wl,-rpath,. -o app
./app
# โ foo() = 42
# Swap in new lib (WEAK foo)
gcc -shared -fPIC -g new/lib.c -Inew -o libfoo.so
./app
# โ foo() = 42 โ same result
# Difference shows in ELF symbol binding:
readelf --syms libfoo.so | grep foo
# old: GLOBAL DEFAULT foo
# new: WEAK DEFAULT foo
Why INFORMATIONAL: WEAK symbols are still exported and resolved normally when no
override exists. The concern is interposition: if another .so or the executable
defines foo as GLOBAL, the WEAK version will be silently overridden at runtime.
Why runtime is COMPATIBLE (matches verdict)¶
WEAK symbols are still exported and resolved normally when no override exists. The concern is interposition โ another .so defining the symbol as GLOBAL silently overrides it. In this demo no override exists, so runtime behavior is identical to GLOBAL binding.
References¶
Source files¶
See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).