Weak symbols let a library or platform layer provide a default function or object that an application can replace with a strong definition of the same name at link time. They are useful for optional callbacks and embedded exception handlers, but they are a compiler-and-linker feature—not portable C or C++ behavior. The key is to distinguish a weak default definition from an undefined weak reference: the first supplies fallback behavior; the second may resolve to zero under ELF rules and must be checked before use.
What weak symbols are used for
A weak symbol is a definition or reference with special linker binding. Under ELF, a weak definition has lower precedence than a global definition. If both define the same symbol, the strong global definition wins without a duplicate-definition error. GCC describes its weak attribute as emitting an external declaration as a weak symbol rather than a global one.
This makes weak symbols useful when one implementation should be the default and an application may replace it without editing the library or startup code. The choice is made at link time, not each time the program runs.
- Overridable library defaults: a library provides a conservative implementation of a callback, and an application supplies a strong implementation when it needs different behavior.
- Embedded exception and interrupt handlers: startup code provides placeholder handlers, while a project defines strong handlers for the interrupts it uses. Arm documents this as a common use of weak function definitions.
- Optional platform hooks: a component can support optional logging, tracing, board identification, or a platform service without requiring every application to implement it.
Override a weak function in C
Provide a weak default
With GCC on a supported target, define the default with __attribute__((weak)). Keep its declaration and definition consistent with the public interface, and make the fallback behavior deliberate rather than silently masking a missing integration.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
/* library.c */
__attribute__((weak)) void platform_log(const char *message)
{
(void)message; /* Deliberate fallback: discard the message. */
}
Provide the application’s strong definition
In a separate application source file, define the same external symbol normally, with the exact same function type and calling convention:
/* app.c */
void platform_log(const char *message)
{
/* Send the message to the application's logging system. */
}
When both object files participate in the link and the toolchain implements these semantics, the application’s strong platform_log definition is selected. The fallback remains available when no strong definition is linked. Do not rely on this mechanism to reconcile incompatible declarations: a mismatched function type is an ABI defect, not a valid override.
Check that the intended definition won
Inspect the final executable or link map rather than assuming the override was included. GNU binutils users can examine symbols with nm or readelf; embedded toolchains typically provide equivalent symbol-table or map-file views. Confirm that the final symbol is the application definition, then test both builds: one with the override and one without it.
Weak default definitions and undefined weak references are different
Weak default definition
A weak default has a body. If no strong definition replaces it, that body is the implementation used by the program. This is generally the straightforward pattern for a default callback or placeholder handler.
Undefined weak reference
An undefined weak symbol has no definition in the current link. ELF permits an unresolved weak symbol to have a zero value. Therefore, an optional function or object referenced this way must be checked before dereferencing or calling it; do not treat an absent hook as though it were a callable no-op.
extern void optional_trace(const char *message)
__attribute__((weak));
void report_event(const char *message)
{
if (optional_trace != 0)
optional_trace(message);
}
Document what happens when the hook is absent, and apply the appropriate presence check before using optional data symbols as well. GCC’s weakref facility describes a weak reference as an alias that does not itself require the target symbol to be defined.
Use weak aliases and weakref deliberately
An alias or weak reference can make one symbol name refer weakly to another. This is useful when a component wants a local or alternate name for a hook without requiring the target definition to exist. It does not remove the need to understand the target toolchain’s alias rules.
- Keep the alias or reference type-compatible with its target.
- Make the target relationship visible in the relevant header or linker documentation.
- Check whether the selected compiler requires an alias target to be defined in the same translation unit, and follow that compiler’s documented syntax.
- Treat a missing weak target as potentially zero under ELF; guard its use where applicable.
Why a weak symbol may not be pulled from a static library
ELF linkers do not extract an object file from a static archive merely to satisfy an undefined weak reference. This differs from the ordinary expectation that a referenced archive member will be brought into the link. As a result, a hook implementation can exist in a library archive and still be absent from the final executable if nothing else causes its member to be selected.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Best Value
Diagnose archive extraction
- Check the link map or symbol table to see whether the archive member containing the hook was included.
- Check whether another strong unresolved reference causes that same member to be extracted.
- Review static-library order and the linker’s documented archive-search behavior for the target toolchain.
- If inclusion is intentional and no ordinary strong reference pulls in the object, use the linker’s force-inclusion option narrowly.
GNU ld provides --whole-archive to force inclusion of every object from an archive. Pair it with --no-whole-archive so the behavior does not unintentionally extend to later libraries:
cc main.o -Wl,--whole-archive -lplatform_hooks
-Wl,--no-whole-archive -o app
Forcing every archive member into a link can increase included code and introduce duplicate definitions or otherwise unnecessary objects. Apply it only to the archive that needs it, and inspect the result.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Weak symbols versus explicit registration
Weak symbols are concise when one link-time default should be replaceable by one application implementation. An explicit function-pointer configuration or registration API is often clearer when selection must happen at runtime, several providers may coexist, or missing configuration should be obvious.
| Decision point | Weak symbol | Explicit registration or function pointer |
|---|---|---|
| Portability | Depends on compiler, object format, and linker support. | Uses ordinary language-level interfaces, though API details still vary. |
| When selection happens | At link time. | Can be configured at runtime or during initialization. |
| Missing implementation | A weak default can hide absence unless its fallback is observable; an undefined weak reference may be zero under ELF. | Can make unconfigured state explicit and report it through the API. |
| Multiple providers | Best suited to one selected strong definition replacing one default. | Can support multiple registrations or selectable providers by design. |
| Testing and diagnosis | Requires checking which symbol the linker selected; archive extraction can affect availability. | Provider choice is explicit in configuration and can be exercised through ordinary API tests. |
Portability and review checklist
GCC documents weak-symbol support for ELF and GNU a.out environments. That does not make __attribute__((weak)) portable C or C++, nor does it guarantee identical behavior from every compiler, object format, or linker. For other toolchains, use the vendor’s documented mechanism and verify its semantics.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Quick Recap
- Confirm the target object format and compiler/linker support.
- Match function type, calling convention, and—for variable overrides—size and alignment.
- Choose intentionally between a weak default definition and an undefined weak reference.
- Guard undefined weak functions or objects before use where the target format permits a zero value.
- Check whether a static archive member is actually extracted; use whole-archive behavior only when justified.
- Inspect the map file or symbol table and test both the fallback and override paths.
- Document the hook’s ABI, ownership, thread-safety expectations, and behavior when no override is present.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

