Dynamic Linking Overview

Dynamic Linking Overview

in

This part provides a high-level overview of why dynamic linking behavior matters for the malloc project, and why allocator interposition behaves differently across platforms. This is a part of dynamic linking investigation series.

The malloc project overrides the standard C allocator by providing strong definitions of malloc, free, calloc, and realloc, statically linked into the final test executable.

void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);

The initial assumption was that doing so would transparently route all allocator calls—both from the executable itself and from dynamically linked libraries—through these implementations.

While this assumption holds on Linux (ELF), it does not hold on macOS (Mach-O). This discrepancy led to unexpected allocator activity during tests, including calls originating from libc, libstdc++, sanitizers, and the test framework itself.

This part of the wiki explains:

  • Why allocator interposition is observable via callsite tracing
  • How ELF dynamic linking causes shared libraries to resolve malloc to the executable’s symbol
  • Why Mach-O’s two-level namespace prevents this by default
  • What this means for cross-platform determinism and allocator correctness

Rather than presenting raw logs or debugger transcripts, this page serves as the conceptual entry point. Detailed investigations and platform-specific mechanics are covered in the following subpages:

If you are reading this to understand why tests behave differently across operating systems, this overview should give you the necessary mental model before diving deeper.

References

‘Chapter 7 Linking’, Randal E. Bryant, David R. O’Hallaron - Computer Systems. A Programmer’s Perspective [3rd ed.]-Pearson (2016)
branch and link
Getting the Return or Frame Address of a Function
malloc_size of Apple’s libmalloc
Code Injection with dyld Interposing