Skip to content

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).