Inferensys

Glossary

Dynamic Library

A dynamic library (or shared library) is a collection of compiled code that is linked to an executable program at runtime, enabling multiple programs to share a single copy and allowing updates without recompiling the main application.
Stylish WeWork-like workspace with hot desks and document wall, professional searching through enterprise knowledge base on a mounted ultrawide display, warm industrial pendants overhead.
Vendor SDK and Intrinsic Mapping

What is a Dynamic Library?

A dynamic library is a fundamental software component in modern systems programming, enabling efficient code sharing and modular application design.

A dynamic library (or shared library) is a compiled binary module containing reusable code and data that is linked at runtime rather than compile time. Unlike a static library, its code is not copied into the final executable. Instead, the executable contains references that the operating system's dynamic linker/loader resolves when the program launches, allowing a single library file on disk to be shared by multiple running applications. This architecture enables efficient memory usage and allows library updates without recompiling dependent applications.

In the context of NPU acceleration, vendor SDKs often provide dynamic libraries (e.g., libvendor_npu.so) that implement the vendor runtime and expose proprietary APIs for hardware management. These libraries abstract the kernel driver and hardware intrinsics, handling low-level tasks like memory transfers between host and NPU, kernel scheduling, and synchronization. The Application Binary Interface (ABI) defines the calling convention for these libraries, ensuring binary compatibility. Developers link their applications against these vendor-provided stub libraries (header files and lightweight import libraries) to access the NPU's functionality at runtime.

VENDOR SDK AND INTRINSIC MAPPING

Key Characteristics of Dynamic Libraries

Dynamic libraries are a core component of modern software deployment, especially for hardware acceleration. Their design enables efficient code sharing, modular updates, and flexible integration with vendor SDKs and runtime environments.

01

Runtime Linking

Unlike static libraries, which are embedded into an executable at compile time, dynamic libraries are linked by the operating system's loader when the program is launched or during execution via functions like dlopen(). This defers symbol resolution, allowing:

  • Multiple applications to share a single copy of the library code in memory.
  • The library to be updated or patched without recompiling the main executable.
  • Conditional loading of functionality based on runtime environment or hardware detection (e.g., loading NPU-specific kernels only if the accelerator is present).
02

Memory Efficiency & Code Sharing

A primary advantage is the reduction of physical memory footprint. The text segment (executable code) of a dynamic library is loaded into RAM once and mapped into the virtual address space of every process that uses it. This is critical in embedded and accelerator contexts where:

  • Multiple processes use the same vendor runtime (e.g., CUDA, ROCm, or a proprietary NPU runtime).
  • System memory is constrained, as on edge devices or within an NPU's host-side memory hierarchy.
  • Read-only code segments can be safely shared across processes, while each process gets its own private copy of writable data segments.
03

Versioning & ABI Stability

Dynamic libraries employ naming and symbol versioning to manage compatibility. The Application Binary Interface (ABI) defines the low-level contract between the library and the executable.

  • Soname: A versioned library name (e.g., libvendor.so.1) embedded in executables to ensure they load a compatible version.
  • Symbol Versioning: Allows multiple versions of the same function to coexist within a single library, letting older programs link to the legacy version while new programs use the updated one.
  • This is essential for vendor SDKs, where the underlying hardware driver or NPU firmware may change, but existing compiled applications must continue to run without modification.
04

Dynamic Loading with `dlopen()`

Beyond automatic loading at program start, programs can explicitly load libraries at runtime using the Dynamic Linking API (dlopen, dlsym, dlclose). This enables plugin architectures and hardware abstraction:

  • A program can probe for an NPU's presence and load the appropriate vendor-specific optimization library (libnpuvendor.so).
  • Function pointers for hardware intrinsics or proprietary APIs can be retrieved via dlsym().
  • This allows a single binary (a fat binary in spirit) to support multiple accelerator backends, falling back to a CPU implementation if no compatible dynamic library is found.
05

Relocation & Position-Independent Code

Because a dynamic library cannot know its final load address in advance, it must be compiled as Position-Independent Code (PIC). PIC uses relative addressing (e.g., PC-relative jumps) and a Global Offset Table (GOT) to reference global data.

  • The linker creates relocation entries in the library. The dynamic loader performs these relocations, patching addresses when the library is loaded into memory.
  • This process adds a small overhead at load time but is essential for security (Address Space Layout Randomization) and for allowing the same library code to be loaded at different virtual addresses in different processes.
06

Dependencies & the Dynamic Linker

Dynamic libraries can have their own dependencies, forming a graph. The dynamic linker (e.g., ld.so on Linux) resolves this graph, loads all required libraries, and performs symbol resolution and relocations.

  • Tools like ldd or objdump -p list a library's DT_NEEDED entries.
  • Dependency hell can occur with conflicting or missing versions. Vendor toolchains often bundle specific versions of their runtime libraries to avoid this.
  • In NPU programming, the main application may depend on a high-level Vendor SDK dynamic library, which in turn depends on a lower-level driver API library and ultimately the kernel driver.
RUNTIME LINKING

How Dynamic Libraries Work in NPU Acceleration

Dynamic libraries are a core software component for deploying optimized neural network workloads on Neural Processing Units (NPUs).

A dynamic library (or shared library) is a collection of pre-compiled code, such as optimized kernels and hardware intrinsics, that is linked to an application at runtime rather than compile time. In NPU acceleration, these libraries contain vendor-provided, highly tuned implementations of fundamental operations (e.g., convolutions, matrix multiplications) that are loaded on-demand by a vendor runtime. This allows multiple AI applications to share a single, memory-efficient copy of the critical acceleration code.

For NPUs, dynamic libraries enable post-deployment optimization and updates; a vendor can ship a new library version with faster kernels without requiring end-users to recompile their models. The Application Binary Interface (ABI) ensures compatibility between the main executable and the library. The dynamic linker/loader resolves symbols and performs relocation when the application starts, mapping library functions to the NPU's physical hardware resources via the driver API.

LINKING STRATEGIES

Dynamic vs. Static Libraries: A Comparison

A technical comparison of the two primary methods for linking external code libraries into an executable program, focusing on implications for deployment, performance, and memory usage in systems programming.

FeatureDynamic Library (.so, .dll, .dylib)Static Library (.a, .lib)

Linking Phase

Runtime (by the loader)

Compile Time (by the linker)

Executable Size

Smaller

Larger (library code is copied in)

Memory Footprint (Multi-Process)

Shared; one copy in RAM

Dedicated; copied per process

Code Updates

Update library file; executables unaffected

Recompile and relink all dependent executables

Deployment Complexity

Higher (must ship/manage library files)

Lower (single, self-contained executable)

Load Time

Slightly slower (runtime resolution)

Faster (no external resolution)

Runtime Performance

Potential overhead for symbol resolution

No runtime linking overhead

Vendor SDK Integration

Easier for updating vendor-provided binaries

Requires re-linking for any SDK update

ABI Compatibility

Critical; version mismatches cause crashes

Not applicable; ABI frozen at link time

DYNAMIC LIBRARY

Frequently Asked Questions

Dynamic libraries are a core component of software deployment, especially for hardware acceleration. This FAQ addresses their role in NPU programming, linking, and optimization.

A dynamic library (or shared library) is a collection of compiled code that is linked to an executable program at runtime, not during compilation. It works by being loaded into memory by the operating system's dynamic linker/loader when the program starts or when a function from the library is first called. The main executable contains references (symbols) to the library's functions, which are resolved to actual memory addresses at load time. This allows multiple programs to share a single copy of the library code in memory, reducing the overall memory footprint and enabling library updates without recompiling the dependent applications.

In the context of NPU acceleration, a vendor's dynamic library (e.g., libVendorNPU.so on Linux or VendorNPU.dll on Windows) contains the optimized, pre-compiled implementations of low-level operations and hardware intrinsics that the main application calls to execute workloads on the accelerator.

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.