Inferensys

Glossary

Dynamic Linking

Dynamic linking is the runtime process where a host application loads a plugin's compiled code (e.g., a shared library or DLL) into memory and resolves its exported symbols to enable execution.
Product manager reviewing autonomous task execution dashboard on laptop, completed tasks visible, casual work session.
PLUGIN ARCHITECTURES

What is Dynamic Linking?

Dynamic linking is a core runtime mechanism in plugin architectures, enabling modular software extension.

Dynamic linking is the runtime process by which a host application loads a plugin's compiled code—such as a shared library (.so) on Linux or a Dynamic-Link Library (.dll) on Windows—into its memory address space and resolves its exported symbols (functions, variables) for execution. This mechanism enables late binding, where the specific implementation of a function is not determined until the moment it is called at runtime, allowing the host to integrate new functionality without recompilation. The host locates the plugin file, maps it into memory, and uses a system loader to connect the plugin's symbols to the host's internal function pointers.

This process is fundamental to plugin architectures, enabling modularity and extensibility in systems like AI agent frameworks. The host defines extension points via stable API contracts, and plugins conform to these interfaces. The system's plugin registry manages discovery, while the loader handles dependency resolution and symbol binding. For security, sandboxing and capability models often restrict plugin resource access. This architecture allows AI agents to dynamically integrate new tools and data connectors, such as those defined by the Model Context Protocol (MCP), without restarting the core reasoning system.

PLUGIN ARCHITECTURES

Key Mechanisms of Dynamic Linking

Dynamic linking is the runtime process of loading a plugin's compiled code into a host application's memory and resolving its symbols for execution. The following mechanisms are fundamental to this process.

01

Symbol Resolution and Relocation

This is the core mechanism where the host's dynamic linker/loader matches undefined references in the plugin's code (symbols) with their actual memory addresses. The process involves:

  • Name Mangling: The linker must understand compiler-generated symbol names to find the correct function or variable.
  • Relocation: After loading the plugin into a memory address, absolute and relative references within its code must be adjusted (relocated) to point to the correct final addresses.
  • Lazy Binding: An optimization where symbol resolution is deferred until the first time a function is actually called, speeding up initial load time.
02

Shared Library/DLL Loading

The physical act of mapping the plugin's compiled binary (e.g., a .so file on Linux, .dll on Windows, .dylib on macOS) from disk into the host process's virtual memory space. Key steps include:

  • Memory Mapping: The operating system maps the library file into the process address space, often using copy-on-write for efficiency.
  • Segment Alignment: Code (.text) and data (.data, .bss) segments are placed in memory pages with appropriate permissions (execute, read, write).
  • Dependency Loading: The linker recursively loads all other shared libraries that the plugin depends on, building a complete dependency graph.
03

Procedure Linkage Table (PLT) & Global Offset Table (GOT)

These are critical data structures used in the Executable and Linkable Format (ELF) common on Unix-like systems to enable position-independent code and lazy binding.

  • Global Offset Table (GOT): A table of pointers that holds absolute addresses of global variables and static data. The linker fills this in after loading.
  • Procedure Linkage Table (PLT): A table of stub functions. The first call to a function jumps to the PLT entry, which then reads the resolved address from the GOT and jumps to it. This enables the lazy binding optimization.
04

Dynamic Section and Dynamic Tags

Within an ELF or PE (Windows Portable Executable) file, a special section (.dynamic) contains an array of tags that serve as instructions for the dynamic linker. This metadata is essential for runtime linking.

  • Needed Libraries: Tags (e.g., DT_NEEDED) list the names of required shared library dependencies.
  • Symbol Tables: Pointers to the dynamic symbol table (.dynsym) and string table (.dynstr) used for symbol resolution.
  • Relocation Tables: Pointers to relocation sections (.rela.dyn, .rela.plt) that tell the linker which addresses need adjustment.
  • Init/Fin Arrays: Pointers to constructor (DT_INIT_ARRAY) and destructor (DT_FINI_ARRAY) functions that run on load and unload.
05

Runtime Linker API (dlopen, dlsym, dlclose)

The programmatic interface exposed to the host application for manual control over dynamic linking. The POSIX standard defines this API.

  • dlopen(): Loads a shared library, resolves its dependencies, and returns a handle. Flags control behavior (e.g., RTLD_LAZY for lazy binding, RTLD_NOW for immediate resolution).
  • dlsym(): Takes a library handle and a symbol name (e.g., "plugin_initialize") and returns the memory address of that symbol.
  • dlclose(): Decrements the reference count on a library. The library is unloaded from memory when its count reaches zero.
  • dlerror(): Retrieves a human-readable error message if any of the above operations fail.
06

Versioning and Symbol Visibility

Mechanisms to manage compatibility and control which symbols are exposed for linking.

  • Symbol Versioning: Allows a single shared library to provide multiple implementations of the same function, tagged with version strings (e.g., memcpy@GLIBC_2.2.5). The linker binds to the version required by the plugin.
  • Default/Hidden Visibility: Compiler attributes (e.g., __attribute__((visibility("default"))) in GCC) control which symbols are exported in the dynamic symbol table. Hiding non-API symbols reduces namespace pollution and improves loading performance.
  • Linker Scripts and Version Maps: Provide fine-grained control over symbol export and versioning, defining which symbols are available under which version tags.
DYNAMIC LINKING

Frequently Asked Questions

Dynamic linking is a core runtime mechanism in plugin architectures, enabling the integration of external functionality into a host application. These questions address its technical implementation, security, and role in AI agent systems.

Dynamic linking is the runtime process by which a host application loads a plugin's compiled code—such as a shared library (.so on Linux, .dylib on macOS) or Dynamic-Link Library (.dll on Windows)—into its memory address space and resolves its symbolic references for execution. It works through a series of precise steps: first, the host locates the plugin's binary file on disk using a plugin registry or manifest. It then calls a system function like dlopen() (POSIX) or LoadLibrary() (Windows) to map the library into memory. The host subsequently resolves the plugin's exported functions—its extension points—by symbol name using dlsym() or GetProcAddress(), obtaining memory addresses it can call directly. This allows the host to bind to the plugin's functionality on-demand, without needing the plugin's code at compile time.

Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.