Linker
The Linker (ld``lld``link.exe) is the final architect of the binary. While the compiler works In isolation on Translation Units (TUs), generating “relocatable object files,” the linker is Responsible for fusing these fragments into a coherent executable memory map.
It performs three critical atomic operations:
- Resolution: Matching “Use” sites (Undefined symbols) to “Definition” sites.
- Relocation: Patching code sections with concrete memory addresses.
- Deduplication: Discarding redundant code generated by templates and inline functions.
1. Symbol Resolution
Section titled “1. Symbol Resolution”Input object files contain a Symbol Table. The linker aggregates these tables into a Global Symbol Table.
The Resolution State Machine
Section titled “The Resolution State Machine”The linker maintains three sets:
- E (Executable): The accumulated object files to be output.
- U (Undefined): References to symbols currently missing a definition.
- D (Defined): Symbols defined in E.
As the linker scans inputs (objects and libraries) from left to right on the command line:
- If input is an Object File (
.o): It adds the file to E. It adds new definitions to D and resolves matching entries in U. Any new undefined references in the object are added to U. - If input is a Static Library (
.a): The linker checks if any symbol in the library’s member objects matches a symbol currently in the U set.
- If a match is found, that specific member object is extracted and added to E.
- If no match is found, the member object is ignored entirely.
:::danger The Archive Order Trap Because static libraries are searched only to resolve currently Pending undefined symbols, order matters. If LibA depends on LibB``LibA must appear before LibB in the linker command.
- Correct:
clang++ main.o -lA -lB - Incorrect:
clang++ main.o -lB -lA(Linker fails: Symbols in A are undefined). :::
Weak vs. Strong vs. Common Symbols
Section titled “Weak vs. Strong vs. Common Symbols”The linker classifies symbols into three categories that determine how duplicates are handled:
Strong symbols: Functions and initialized global variables. There must be exactly one strong Definition for each symbol across all object files. Duplicate strong definitions cause a “multiple Definition” linker error.
// Strong: initialized globalint config_value = 42;
// Strong: functionvoid process() { }Weak symbols: Uninitialized globals (tentative definitions), or symbols explicitly annotated With __attribute__((weak)). If both a strong and weak definition exist, the strong one wins. Multiple weak definitions are permitted and the linker picks one arbitrarily.
// Weak: uninitialized global (tentative definition)int tentative_value;
// Weak: explicit annotation (GCC/Clang)__attribute__((weak))void optional_hook() { }Common symbols: These are a special case of tentative definitions. When GCC encounters an Uninitialized global in a C translation unit, it emits it as a “common” symbol (in the COM section Rather than BSS). Common symbols can be merged: if multiple TUs define int x; without Initialization, the linker allocates storage once and aligns to the largest requested alignment. The -fno-common flag (now default in GCC 10+) disables this behavior and makes uninitialized globals Ordinary weak symbols instead.
// Before GCC 10 (default -fcommon):// File A: int x; -> COMMON symbol// File B: int x; -> COMMON symbol// Linker merges them into a single BSS allocation
// GCC 10+ (default -fno-common):// File A: int x; -> weak BSS symbol// File B: int x; -> weak BSS symbol// Multiple weak definitions: OK, linker picks oneSymbol Visibility
Section titled “Symbol Visibility”Symbol visibility controls which symbols are exported from shared libraries (.so``.dll). This Affects both dynamic linking and name mangling.
| Visibility | ELF Flag | Meaning |
|---|---|---|
| Default | (none) | Exported; may be interposed by LD_PRELOAD |
| Hidden | __attribute__((visibility("hidden"))) | Not exported; internal to the DSO |
| Protected | __attribute__((visibility("protected"))) | Exported but cannot be interposed |
| Internal | (implementation-defined) | Not exported; may enable more aggressive optimization |
// Hide all symbols by default, export only the API#pragma GCC visibility push(hidden)
__attribute__((visibility("default")))void public_api_function();
// Internal: not exported, not interposablevoid internal_helper();# CMake: hide all symbols by defaultset(CMAKE_CXX_VISIBILITY_PRESET hidden)set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)Duplicate Symbol Detection
Section titled “Duplicate Symbol Detection”When the linker encounters two strong definitions of the same symbol, it emits a fatal error. The Error message includes the object files containing the conflicting definitions:
duplicate symbol '_ZN3foo7processEv' in: CMakeFiles/App.dir/A.cpp.o CMakeFiles/App.dir/B.cpp.old: fatal error: duplicate symbolCommon causes include:
- Accidentally defining a non-inline function in a header file included by multiple TUs.
- Forgetting
inlineon a function defined in a header. - Violating the ODR by defining a struct differently across TUs (detected at link time only if the mangled names differ).
Proof: Linker ODR Violation Detection Mechanism
Section titled “Proof: Linker ODR Violation Detection Mechanism”The linker detects ODR violations through the One Definition Rule’s structural requirements. Per [N4950 S6.3], if two declarations of the same entity differ, the program is ill-formed (no Diagnostic required). The linker provides a partial diagnostic through its symbol resolution:
- Strong symbol conflict: If two TUs define the same function (same mangled name) as a strong symbol, the linker detects a “multiple definition” error because two global symbol table entries have the same key.
- COMDAT deduplication: For inline functions and templates, the compiler places each instantiation in a COMDAT section keyed by the mangled name. The linker keeps exactly one copy. If two COMDAT sections have the same key but different sizes or contents, the linker does not detect this (it keeps one arbitrarily). This is a silent ODR violation.
- The silent case: If two TUs define
struct S { int x; };in one andstruct S { double x; };in the other, and no function signature encodesSdifferently (e.g., both TUs only useS*), the linker cannot detect the violation. The mangled names are identical. This is the most dangerous form of ODR violation.
Conclusion: The linker detects ODR violations only when they produce different mangled names. Structural ODR violations (same name, different definitions) that do not affect function signatures Are invisible to the linker. This is why -Wodr (GCC) and modules are important for ODR safety.
Archive Files and --whole-archive
Section titled “Archive Files and --whole-archive”Static libraries (.a files on Unix, .lib files on Windows) are not linked as a single unit. They Are archives of individual object files. The linker extracts only the member objects that Satisfy currently pending undefined references.
This default behavior causes problems when a library provides a plugin or callback mechanism: member Objects that register themselves via global constructors may never be pulled in because no symbol in U references them.
# Problem: libplugin.a defines init_plugin() via a global constructor,# but nothing in main.o references init_plugin() explicitly.clang++ main.o -lplugin # init_plugin() is NEVER extracted
# Solution: force the linker to include ALL membersclang++ main.o -Wl,--whole-archive -lplugin -Wl,--no-whole-archiveThe --no-whole-archive after the library is critical. Forgetting it causes every subsequent Library on the command line to be linked in its entirety, bloating the binary.
2. Relocation
Section titled “2. Relocation”Compilers generate object code assuming a start address of 0x0. Instructions referring to data or Other functions use placeholder values. Relocation is the process of patching these placeholders With actual addresses once the final memory layout is determined.
Relocation Entries
Section titled “Relocation Entries”The compiler generates a .rela.text section containing instructions for the linker.
- Instruction: “At offset
0x42in section.textInsert the difference between the address of symbolfooand the current instruction pointer (RIP).”
Relocation Types (x86_64)
Section titled “Relocation Types (x86_64)”R_X86_64_PC32 (Relative): Used for function calls (
call) and data access (lea) within the same binary. The value patched is (Symbol + Addend - Place). This enables Position Independent Code (PIC), allowing the binary to be loaded at any virtual address (ASLR).R_X86_64_64 (Absolute): Used for static data pointers (e.g., jump tables). Requires load-time patching if the binary base address changes.
R_X86_64_GOTPCREL (GOT-relative): Used for accessing global variables through the GOT in position-independent code. The instruction loads the GOT entry address, then loads the value from the GOT.
The PLT and GOT (Dynamic Linking)
Section titled “The PLT and GOT (Dynamic Linking)”When code references a symbol in a Shared Library (.so), the address is unknown until runtime. The linker cannot patch the code directly. Instead, it generates:
- Global Offset Table (GOT): A data section (
.got) acting as a directory of addresses. - Procedure Linkage Table (PLT): A code section (
.plt) containing stubs.
Mechanism:
- Code calls
printf(in libc). - The call jumps to
printf@plt(stub). - The stub jumps to the address stored in
printf@got. - Lazy Binding: Initially, the GOT points back to the dynamic linker resolver. On the first call, the resolver finds the actual
printfaddress, updates the GOT, and executes the function. Subsequent calls jump directly.
Lazy vs Eager Binding
Section titled “Lazy vs Eager Binding”By default, ELF uses lazy binding (resolve symbols on first call). This can be disabled:
# Eager binding: resolve all symbols at load timeLD_BIND_NOW=1 ./app
# Compile-time: mark all GOT entries as requiring immediate resolutionclang++ -Wl,-z,now main.o -lfooEager binding eliminates the first-call overhead and makes the startup behavior deterministic, which Is important for security (prevents GOT overwrite attacks from redirecting control flow) and for Real-time systems (no unpredictable latency on first function call).
3. Deduplication (COMDAT Folding)
Section titled “3. Deduplication (COMDAT Folding)”C++ templates pose a unique challenge. If std::vector<int>::push_back is instantiated in A.cpp And B.cppBoth object files contain the machine code for that function. Naively linking them Would result in a “Multiple Definition” error.
COMDAT Sections
Section titled “COMDAT Sections”The compiler marks template instantiations and inline functions with a special flag: COMDAT (Common Block).
- Rule: “This section defines symbol X. If you have already seen a COMDAT for X, discard this section. If not, keep it.”
- Result: The final binary contains exactly one copy of the template code.
Per [N4950 S6.3], inline functions with external linkage may be defined in multiple translation Units provided all definitions are identical. COMDAT is the linker mechanism that enforces this by Keeping only one copy.
Identical Code Folding (ICF)
Section titled “Identical Code Folding (ICF)”Modern linkers (Gold, LLD, Mold) go further. They detect functions that are distinct in C++ but Compile to identical machine code.
Example: std::vector<int> and std::vector<unsigned int> often generate identical machine Code since they have the same element size and layout.
ICF Mechanism:
- The linker hashes the
.textcontent of every section. - If hashes match, it performs a byte-by-byte comparison.
- If identical, it keeps one copy and updates the symbol table so both
vector<int>::push_backandvector<unsigned int>::push_backpoint to the same address.
CMake Configuration:
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") # Enable ICF on LLD/Gold add_link_options("-Wl,--icf=all")endif():::caution ICF can break programs that compare function pointers for identity. If f() and g() Are folded into the same address, &f == &g becomes true even though they are distinct functions. This is rare but possible. Use -Wl,--icf=safe to fold only functions with identical relocations. :::
4. Static vs. Shared Libraries
Section titled “4. Static vs. Shared Libraries”Static Libraries (.a / .lib)
Section titled “Static Libraries (.a / .lib)”A static library is an archive of object files. At link time, the linker extracts the needed members And embeds them directly into the final binary.
- Pros: No runtime dependency; deterministic behavior; simpler deployment.
- Cons: Binary bloat (unused code may be pulled in); no sharing across processes; updates require re-linking.
Shared Libraries (.so / .dll)
Section titled “Shared Libraries (.so / .dll)”A shared library is a fully linked binary that is loaded at runtime by the dynamic linker (ld.so On Linux, ntdll.dll on Windows).
- Pros: Smaller executables; code sharing across processes (one physical copy in RAM); updates without re-linking.
- Cons: Runtime dependency (missing
.socauses launch failure); symbol interposition complexity; slight startup cost for dynamic resolution.
Link Order Significance on Linux
Section titled “Link Order Significance on Linux”The linker processes inputs strictly left to right. This has a profound effect when mixing object Files and libraries:
# main.o references func_A() in libA and func_B() in libB# libA also references func_B() in libB
# CORRECT: main.o first, then dependent libs in dependency orderclang++ main.o -lA -lB
# WRONG: libB before libAclang++ main.o -lB -lA# libB is scanned: no pending undefined refs -> nothing extracted# libA is scanned: func_A extracted, now func_B is pending# End of input: func_B is still undefined -> LINKER ERROR
# WRONG: libraries before object filesclang++ -lA -lB main.o# libA scanned: no pending undefined -> nothing extracted# libB scanned: no pending undefined -> nothing extracted# main.o added: func_A and func_B become pending# End of input: both undefined -> LINKER ERRORRule of thumb: Object files first, then libraries ordered by dependency (dependents before Dependencies). Circular dependencies between libraries require --start-group / --end-group:
clang++ main.o -Wl,--start-group -lA -lB -Wl,--end-groupThis tells the linker to rescan the group until no more symbols can be resolved.
5. Modern Linkers: LLD vs. Mold vs. Gold
Section titled “5. Modern Linkers: LLD vs. Mold vs. Gold”GNU ld (BFD)
Section titled “GNU ld (BFD)”The original GNU linker. Written in C, slow for large projects, but universally available. Supports All obscure linker script features.
A faster linker written in C++, part of GNU Binutils. Introduced the plugin interface for LTO (Link Time Optimization). Largely superseded by LLD.
LLD (LLVM)
Section titled “LLD (LLVM)”The LLVM linker. Written in C++. Key advantages:
- Speed: 2-10x faster than GNU ld for large projects.
- Cross-platform: Supports ELF (Linux), COFF (Windows), Mach-O (macOS), and WebAssembly.
- Diagnostics: Improved error messages with source locations.
# CMake: use LLDcmake -DCMAKE_LINKER=lld ..# Or via compiler flag:clang++ -fuse-ld=lld main.o -lA -lBA modern linker designed for speed. Written in C++. Claims to be 5-100x faster than GNU ld.
cmake -DCMAKE_LINKER=mold ..# Or:clang++ -fuse-ld=mold main.o -lA -lB| Feature | GNU ld (BFD) | Gold | LLD | Mold |
|---|---|---|---|---|
| Language | C | C++ | C++ | C++ |
| ELF Support | Full | Full | Full | Full |
| COFF Support | No | No | Yes (lld-link) | No |
| Mach-O Support | No | No | Yes (ld64.lld) | No |
| Linker Scripts | Full | Partial | Most | Partial |
| Speed | Baseline | 2-5x | 2-10x | 5-100x |
| LTO | Via plugin | Native | Native | Via plugin |
6. Linker Scripts
Section titled “6. Linker Scripts”A linker script (ld syntax) controls the layout of sections in the final binary. While most Developers never write them, understanding them is essential for embedded systems and OS Development.
/* Minimal linker script */ENTRY(_start)
SECTIONS{ . = 0x100000; /* Base address: 1 MB */ .text : { *(.text) } /* All .text sections concatenated */ .rodata : { *(.rodata) } .data : { *(.data) } .bss : { __bss_start = .; *(.bss) __bss_end = .; }}Key directives:
ENTRY(symbol): Sets the entry point..(location counter): Represents the current VMA (Virtual Memory Address).*(.section): Wildcard pattern matching all input sections named.section.PROVIDED(symbol) = value: Define a symbol only if not already defined.KEEP(section): Prevent garbage collection from discarding the section (critical for.init_array).
To inspect the default linker script for your target:
ld --verbose | grep -A100 "SECTIONS"7. LTO (Link Time Optimization)
Section titled “7. LTO (Link Time Optimization)”LTO allows the linker to perform whole-program optimization by serializing the compiler’s Intermediate representation (IR) into the object file and re-running optimization passes at link Time.
How LTO Works
Section titled “How LTO Works”- Compilation: The compiler generates LLVM IR (or GCC GIMPLE) instead of machine code and embeds it in a
.ofile alongside a thin object file for fast linking without LTO. - Linking: The linker extracts the IR from all
.ofiles, merges them, and runs interprocedural optimization (inlining, dead code elimination, devirtualization). - Codegen: The optimized IR is compiled to machine code and linked.
LTO Types
Section titled “LTO Types”| Type | Description | Build Time | Binary Quality |
|---|---|---|---|
| Full LTO | Merges all IR into one unit | Slow (high memory) | Best |
| ThinLTO | Parallel summary-based optimization | Moderate | Near-full LTO |
# CMake: enable LTOset(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
# Or per-target:set_target_properties(app PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)LTO can detect ODR violations that the linker alone cannot: the merged IR allows the compiler to Compare type definitions across TUs. GCC’s -Wodr and Clang’s -Wodr flags enable this diagnostic.
8. Name Demangling
Section titled “8. Name Demangling”The linker operates on Mangled Names (decorated names that encode namespace, class, and argument Types).
- Source:
void foo::bar(int) - Mangled (Itanium):
_ZN3foo3barEi
Linker errors report the mangled name, which is unreadable. Tools like c++filt translate them Back.
Diagnostic Workflow:
Error:
undefined reference to _ZN3foo3barEiDemangle:
Terminal window c++filt _ZN3foo3barEi# Output: foo::bar(int)Inspect: Use
nmto find which object file provides (or fails to provide) the symbol.Terminal window nm -C --defined-only libfoo.a | grep "foo::bar"
9. Debugging Undefined Reference Errors
Section titled “9. Debugging Undefined Reference Errors”Undefined reference errors are the most common linker errors. A systematic debugging approach:
Step 1: Demangle the Symbol
Section titled “Step 1: Demangle the Symbol”# Pipe the error through c++filtclang++ main.o -lfoo 2>&1 | c++filtStep 2: Verify the Symbol Exists
Section titled “Step 2: Verify the Symbol Exists”# Check if the symbol is defined in any object file or librarynm -C libfoo.a | grep "missing_symbol"nm -C main.o | grep "missing_symbol"Step 3: Check Link Order
Section titled “Step 3: Check Link Order”Ensure the object file referencing the symbol appears before the library providing it on the command Line.
Step 4: Check Name Mangling Compatibility
Section titled “Step 4: Check Name Mangling Compatibility”If the symbol is defined in a C library but declared in C++ code without extern "C"The C++ Compiler will emit a mangled name while the library exports an unmangled name.
// WRONG: C++ mangling applied to C functionextern void c_library_init(); // Mangled as: _Z14c_library_initv
// CORRECT: disable mangling for C interfaceextern "C" void c_library_init(); // Unmangled: c_library_initStep 5: Check Visibility and Export Maps
Section titled “Step 5: Check Visibility and Export Maps”Symbols may be hidden by -fvisibility=hidden or by .def / version scripts. Use nm -D to check The dynamic symbol table:
# Dynamic symbols only (what's exported from a .so)nm -D libfoo.so | grep "missing_symbol"Symbol Type Comparison
Section titled “Symbol Type Comparison”| nm Symbol Type | Meaning | Typical Source |
|---|---|---|
T / t | Text (code) section | Function definition |
D / d | Data section | Initialized global variable |
B / b | BSS section | Uninitialized global variable |
U | Undefined | External reference (needs resolution) |
W / w | Weak symbol | Tentative definition or __attribute__((weak)) |
A | Absolute | Linker script symbol |
V / v | Weak object (ELF) | Weak symbol definition |
Common Pitfalls
Section titled “Common Pitfalls”- Link order matters: Object files before libraries, dependents before dependencies. This is the single most common source of linker errors on Linux.
--whole-archivewithout--no-whole-archive: Forgets to close the whole-archive scope, causing massive binary bloat.- Mismatched
extern "C": Forgettingextern "C"when calling C code from C++ causes undefined reference to the mangled name. - Inline functions in headers without
inline: Defining a non-inline function in a header included by multiple TUs causes duplicate symbol errors. - Static library not rebuilt after header change: Changing a header only recompiles TUs that include it. If the static library was not rebuilt, stale object files may cause mysterious errors.
- LTO with incompatible object files: Mixing LTO and non-LTO object files from different compilers can cause linker errors. Ensure all objects are compiled with the same LTO settings.
- ICF folding distinct functions: Identical Code Folding may merge functionally distinct functions that happen to compile to the same machine code, breaking function pointer comparisons.
10. Version Scripts and Symbol Versioning
Section titled “10. Version Scripts and Symbol Versioning”ELF shared libraries can use version scripts to control symbol visibility and provide ABI Versioning. This is critical for maintaining backward compatibility when evolving a library’s API.
Basic Version Script
Section titled “Basic Version Script”VERS_1.0 { global: foo; bar; local: *;};
VERS_2.0 { global: baz;} VERS_1.0;Usage:
# Compile and link with version scriptclang++ -shared -Wl,--version-script=libfoo.ver -o libfoo.so foo.cppHow Symbol Versioning Works
Section titled “How Symbol Versioning Works”The linker assigns a version tag to each symbol in the shared library. When a program links against The library, it records which version of each symbol it was linked against. At runtime, the dynamic Linker verifies that the requested version is available.
This allows the library to introduce new symbols (in VERS_2.0) without breaking existing programs That depend on VERS_1.0 symbols. If a symbol is removed or changed in VERS_2.0The dynamic Linker detects the version mismatch and reports an error rather than silently producing incorrect Behavior.
Version Script for Hiding Symbols
Section titled “Version Script for Hiding Symbols”Version scripts are an alternative to -fvisibility=hidden for controlling which symbols are Exported:
{ global: public_api_*; local: *;};This exports only symbols matching public_api_* and hides everything else, without requiring Source-level __attribute__((visibility("hidden"))) annotations.
11. Linker Deficiencies and Common Error Patterns
Section titled “11. Linker Deficiencies and Common Error Patterns””undefined reference to vtable for Foo”
Section titled “”undefined reference to vtable for Foo””This error occurs when a class with virtual methods is declared but the compiler-generated virtual Table and typeinfo are not linked in. Common causes:
- Virtual method declared but not defined: If
Foohas a virtual method declared in the header but the definition is missing from all TUs, the compiler emits a reference tovtable for Foobut no definition. The linker reports the error. - First virtual method is defined out-of-line but not linked: The compiler places the vtable in the TU that defines the first non-pure virtual function. If that TU is not linked, the vtable is missing.
”relocation truncated to fit: R_X86_64_PC32 against symbol”
Section titled “”relocation truncated to fit: R_X86_64_PC32 against symbol””This error occurs when a 32-bit relative relocation is used for a symbol that is too far away (more Than 2 GB apart in the virtual address space). Common causes:
- Large binaries: If the
.textsection exceeds 2 GB, references from one end to the other exceed the 32-bit relative offset range. - Missing
-fPIC: Non-PIC code in shared libraries uses absolute addresses that may require 64-bit relocations.
Fix: Compile with -fPIC and/or use -mcmodel=medium or -mcmodel=large for large binaries.
”multiple definition of __builtin_expect”
Section titled “”multiple definition of __builtin_expect””This error occurs when a TU is compiled with -fno-builtin or with different compiler versions that Handle builtins differently. The builtin functions may be emitted as strong symbols in multiple Object files. Fix by ensuring consistent compiler flags across all TUs.
12. Link Map Files
Section titled “12. Link Map Files”Link map files provide a detailed dump of the linker’s decisions, showing where each symbol is Placed in the output binary:
# Generate a link map fileclang++ -Wl,-Map=output.map main.o -lfoo -o app
# Inspect for specific symbolsgrep "foo\|bar" output.mapThe map file contains:
- Memory addresses of each section and symbol.
- Archive member extraction decisions (which
.ofiles from.awere pulled in and why). - Symbol resolution (which definition satisfied each undefined reference).
- Total binary size breakdown by section.
Link map files are invaluable for debugging linker issues in large projects where manually tracing Symbol resolution is impractical.
13. Link Time Optimization (LTO) and ODR Detection
Section titled “13. Link Time Optimization (LTO) and ODR Detection”As mentioned in Section 7, LTO can detect ODR violations that the linker alone cannot. When LTO is Enabled, the linker merges the intermediate representation (IR) from all object files and can Compare type definitions across TUs:
# GCC: enable ODR diagnosticsg++ -flto -Wodr main.o utils.o -o app
# Clang: LTO ODR detection is on by defaultclang++ -flto main.o utils.o -o appWhen -Wodr detects a mismatch (e.g., struct S defined with different members in two TUs), it Reports the conflicting definitions with source locations. This is a significant improvement over The linker’s silent acceptance of structurally different ODR violations.
However, -Wodr has limitations:
- It only checks types that are used in LTO-visible functions. If a type is only used in non-inline functions that are not optimized across TUs, the violation may go undetected.
- It produces false positives for types that are intentionally defined differently in different contexts (e.g.,
#ifdefguards that produce different struct layouts). - It significantly increases link time because the linker must parse and compare IR from all TUs.
14. The --wrap Linker Flag
Section titled “14. The --wrap Linker Flag”The --wrap flag allows intercepting calls to a specific symbol at link time. This is used for Testing (mocking) and for runtime instrumentation:
# Redirect all calls to 'malloc' to '__wrap_malloc'clang++ -Wl,--wrap=malloc app.o -o app// In the application or a test harness:extern "C" void* __wrap_malloc(size_t size) { // Custom implementation (logging, tracking, etc.) return __real_malloc(size);}
extern "C" void* __real_malloc(size_t size);The linker rewrites every call to malloc to call __wrap_malloc instead. The __real_malloc Symbol is provided by the original library and can be called from within the wrapper. This mechanism Does not require modifying the original source code.
:::caution --wrap operates at the symbol level, not the function level. If malloc is inlined by The compiler, the wrapper will not intercept the inlined call. Use -fno-inline on the wrapping TU Or compile the wrapped TU separately without LTO.
See Also
Section titled “See Also”Summary
Section titled “Summary”This topic covers the essential concepts and techniques related to linker, including key principles and practical applications.
Key concepts include:
- core concepts and definitions
- key principles and frameworks
- practical applications
- common techniques and methods
- evaluation and critical analysis
A thorough understanding of these concepts, combined with regular practice and review, is essential for mastery of this topic.
Worked Examples
Section titled “Worked Examples”Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.
:::