C++ Dynamic Linking

7 min

Master dynamic linking and runtime library loading with interactive visualizations.

Best viewed on desktop for optimal interactive experience

Dynamic Linking at Runtime

Dynamic linking defers library loading until program execution, enabling code sharing and smaller executables.

Dynamic Library Loading

Available Shared Libraries

libc.so.6
v2.312.1 MB
printfmallocfree+2 more
libm.so.6
v2.311.5 MB
Depends on: libc.so.6
sincossqrt+2 more
libpthread.so.0
v2.31156 KB
Depends on: libc.so.6
pthread_createpthread_joinpthread_mutex_lock
libstdc++.so.6
v10.21.9 MB
Depends on: libc.so.6, libm.so.6
std::coutstd::vectorstd::string+1 more

Loading Process

Click "Load" to simulate dynamic loading

Dynamic Linker Environment

LD_LIBRARY_PATH=/custom/lib:/usr/local/lib
LD_PRELOAD=./mylib.so
LD_DEBUG=libs,bindings

Static vs Dynamic

Static Linking

  • Code copied into executable
  • Larger file size
  • No runtime dependencies
  • Faster startup

Dynamic Linking

  • References to shared libraries
  • Smaller executables
  • Runtime dependencies
  • Memory sharing between processes

Creating Shared Libraries

# Compile with PIC (Position Independent Code) g++ -fPIC -c mylib.cpp # Create shared library g++ -shared -o libmylib.so mylib.o # Link against library g++ main.cpp -L. -lmylib -o program # Run with library path LD_LIBRARY_PATH=. ./program

Runtime Loading with dlopen

#include <dlfcn.h> // Load library at runtime void* handle = dlopen("libplugin.so", RTLD_LAZY); // Get function pointer typedef int (*func_t)(int); func_t func = (func_t)dlsym(handle, "function"); // Call function int result = func(42); // Unload library dlclose(handle);

GOT/PLT Mechanism

Dynamic symbols are resolved through:

  • PLT (Procedure Linkage Table): Jump stubs
  • GOT (Global Offset Table): Address storage

First call:

  1. Call goes to PLT stub
  2. PLT jumps to GOT entry
  3. GOT points back to resolver
  4. Resolver finds symbol
  5. Updates GOT with real address

Subsequent calls go directly through GOT.

Environment Variables

# Library search path LD_LIBRARY_PATH=/custom/lib:$LD_LIBRARY_PATH # Preload libraries LD_PRELOAD=./mylib.so ./program # Debug dynamic linker LD_DEBUG=libs ./program # Force immediate binding LD_BIND_NOW=1 ./program

Troubleshooting

Library Not Found

# Check dependencies ldd program # Find missing library ldconfig -p | grep libname # Add library path export LD_LIBRARY_PATH=/path/to/lib

Symbol Version Issues

# Check symbol versions objdump -T library.so # Force specific version patchelf --replace-needed old.so new.so program

Best Practices

  1. Version your libraries: Use SONAME
  2. Minimize dependencies: Reduce complexity
  3. Use RPATH carefully: Consider security
  4. Document dependencies: Help users
  5. Test with ldd: Verify before deployment

Next Steps

If you found this explanation helpful, consider sharing it with others.

Mastodon