ADVERTISEMENT
Responsive Ad Unit • Systems Architecture & Low-Level Engineering

Shared Libraries

Shared libraries allow multiple programs to use the same compiled library code stored only once in memory and on disk. This reduces executable size, saves RAM, simplifies software updates, and enables runtime loading of functionality.

Learning Objectives

  • Understand shared libraries.
  • Compare static and shared libraries.
  • Learn dynamic linking.
  • Understand the dynamic loader.
  • Learn library search paths.
  • Prepare for runtime loading APIs.

1. What is a Library?

A library is a collection of reusable compiled functions and data that can be linked with one or more programs. Libraries reduce code duplication and promote software reuse.

2. Types of Libraries

Type Description
Static Library Copied into the executable during linking.
Shared Library Loaded dynamically at program startup or runtime.

3. Static Linking

During static linking, the linker copies the required library code directly into the executable. Each executable contains its own copy of the library functions.

Source Code ↓ Compiler ↓ Object File ↓ Static Library (.a) ↓ Linker ↓ Executable

4. Shared Library

A shared library is stored separately from the executable. The executable contains references to the shared library, which is loaded into memory by the operating system when required.

Executable ↓ Shared Library (.so) ↓ Dynamic Loader ↓ Memory

5. Static vs Shared Libraries

Feature Static Shared
Executable Size Larger Smaller
Memory Usage Higher Lower
Runtime Dependency No Yes
Library Updates Requires rebuilding Usually not required
Startup Time Usually Faster May require loading

6. Dynamic Linking

Dynamic linking resolves library references when a program starts or when a library is loaded during execution. Only the required shared library is mapped into memory.

7. Dynamic Loader

The dynamic loader is responsible for locating required shared libraries, loading them into memory, resolving external symbols, and transferring control to the application. On Linux, this loader is commonly implemented as ld.so or ld-linux.so, depending on the system architecture.

8. ELF Overview

Most modern UNIX and Linux systems use the Executable and Linkable Format (ELF) for executables, object files, and shared libraries. ELF stores metadata describing program sections, symbols, relocation information, and library dependencies.

9. Library Search Path

When a program starts, the dynamic loader searches for required shared libraries using configured search paths. Typical search locations include:

  • /lib
  • /usr/lib
  • /usr/local/lib
  • Directories configured by the system.
  • Directories specified through environment variables (platform dependent).

10. Interview Questions

  1. What is a shared library?
  2. How does a shared library differ from a static library?
  3. What is dynamic linking?
  4. What is the purpose of the dynamic loader?
  5. What is ELF?
  6. Why are shared libraries memory efficient?
  7. Which file extension is commonly used for shared libraries?
  8. Why are static executables generally larger?
  9. Where does the loader search for shared libraries?
  10. Why are shared libraries widely used in modern operating systems?

11. Runtime Dynamic Loading

Unlike normal dynamic linking, runtime dynamic loading allows an application to load a shared library whenever it is needed. This enables plug-in architectures and optional functionality without requiring the library to be loaded when the application starts.

12. dlopen()

The dlopen() function loads a shared library into the current process and returns a handle used for future operations.

#include <dlfcn.h> void *dlopen(const char *filename, int flags);

13. Common dlopen() Flags

Flag Description
RTLD_LAZY Resolve symbols only when first used.
RTLD_NOW Resolve all symbols immediately.
RTLD_GLOBAL Export loaded symbols for future libraries.
RTLD_LOCAL Keep symbols local to the loaded library.

14. dlsym()

The dlsym() function searches a loaded shared library for a symbol such as a function or global variable.

#include <dlfcn.h> void *dlsym(void *handle, const char *symbol);

15. dlclose()

The dlclose() function decreases the reference count of a dynamically loaded library. When the reference count reaches zero, the implementation may unload the library.

#include <dlfcn.h> int dlclose(void *handle);

16. dlerror()

The dlerror() function returns a human-readable string describing the most recent dynamic loading error.

#include <dlfcn.h> char *dlerror(void);

17. Runtime Symbol Resolution

Application ↓ dlopen() ↓ Shared Library Loaded ↓ dlsym() ↓ Function Pointer ↓ Function Call ↓ dlclose()

18. Example Using dlopen()

#include <stdio.h> #include <dlfcn.h> int main(void) { void *handle; handle = dlopen("./libmath.so", RTLD_NOW); if (handle == NULL) { printf("%s\n", dlerror()); return 1; } printf("Library Loaded Successfully\n"); dlclose(handle); return 0; }

19. Example Using dlsym()

typedef int (*add_func)(int, int); add_func add; add = (add_func) dlsym(handle, "add"); if (add == NULL) { printf("%s\n", dlerror()); } printf("%d\n", add(10, 20));

20. Interview Questions

  1. What is the purpose of dlopen()?
  2. What does dlsym() return?
  3. Why is a function pointer required with dlsym()?
  4. What is the purpose of dlerror()?
  5. What happens when dlclose() is called?
  6. What is the difference between RTLD_NOW and RTLD_LAZY?
  7. What is runtime symbol resolution?
  8. Which header declares the runtime loading functions?
  9. How are plug-in architectures implemented using shared libraries?
  10. Why should every call to dlopen() eventually be matched by dlclose()?

21. Building a Shared Library

A shared library is typically compiled as Position Independent Code (PIC) and then linked into a shared object file.

gcc -fPIC -c math.c gcc -shared -o libmath.so math.o

22. Position Independent Code (PIC)

Position Independent Code (PIC) allows executable instructions to run correctly regardless of the memory address where the library is loaded. This enables the operating system to load the same shared library into different virtual addresses for different processes.

Source Code ↓ Compile with -fPIC ↓ Position Independent Object ↓ Shared Library (.so) ↓ Loaded Anywhere in Memory

23. Creating a Static Library

Static libraries are archive files that contain one or more object modules. The ar utility is commonly used to create archive files.

gcc -c math.c ar rcs libmath.a math.o

24. Linking with Libraries

Applications can link against libraries using the -L and -l compiler options.

gcc main.c -L. -lmath -o app

Where:

Option Description
-L Specifies a library search directory.
-l Specifies the library name without the lib prefix or extension.

25. Runtime Library Search

Executable ↓ Dynamic Loader ↓ Search Library Paths ↓ Locate libmath.so ↓ Load into Memory ↓ Resolve Symbols

26. Linux Library Commands

Command Purpose
ldd app Display shared library dependencies.
ldconfig Update shared library cache.
nm libmath.so Display exported symbols.
objdump -T libmath.so Display dynamic symbol table.
readelf -d libmath.so Display dynamic section.

27. Library Development Workflow

Write Source ↓ Compile ↓ Create Library ↓ Link Application ↓ Execute Program ↓ Dynamic Loader Loads Library

28. Best Practices

  • Compile shared libraries using -fPIC.
  • Export only the symbols required by users of the library.
  • Maintain backward compatibility whenever possible.
  • Always verify the return value of dlopen().
  • Release dynamically loaded libraries using dlclose().
  • Document exported APIs clearly.

29. Common Programming Mistakes

  • Building shared libraries without -fPIC.
  • Forgetting to link with the required library.
  • Ignoring errors returned by dlopen().
  • Using incorrect library search paths.
  • Calling dlsym() with an invalid symbol name.
  • Forgetting to call dlclose().

30. Interview Questions

  1. Why is -fPIC required for shared libraries?
  2. What is Position Independent Code?
  3. How is a static library created?
  4. What is the purpose of the ar utility?
  5. What does the -L compiler option do?
  6. Why is the -l option used without the lib prefix?
  7. Which Linux command displays shared library dependencies?
  8. What information does nm display?
  9. What is the purpose of ldconfig?
  10. Why should only necessary symbols be exported from a shared library?

31. Runtime Loading API Comparison

Function Purpose
dlopen() Load a shared library.
dlsym() Locate a symbol within a loaded library.
dlerror() Retrieve the last dynamic loading error.
dlclose() Release a dynamically loaded library.

32. Static vs Dynamic Linking Comparison

Feature Static Linking Dynamic Linking
Executable Size Larger Smaller
Memory Usage Separate copy per executable Shared among processes
Program Startup No runtime library loading Dynamic loader resolves libraries
Library Updates Application must be rebuilt Usually only library replacement is required*
Runtime Loading Not supported Supported through dlopen()

*Provided the updated library remains binary compatible with the application.

33. Complete Shared Library Workflow

Source Code ↓ Compile (-fPIC) ↓ Object File ↓ Shared Library (.so) ↓ Executable ↓ Dynamic Loader ↓ dlopen() ↓ dlsym() ↓ Function Execution ↓ dlclose()

34. Linux Commands Summary

Command Purpose
ldd Show shared library dependencies.
ldconfig Update and display shared library cache.
nm Display symbol table information.
objdump -T Display exported dynamic symbols.
readelf -d Display ELF dynamic section.
file Identify executable and library file types.

35. Best Practices Review

  • Compile shared libraries using -fPIC.
  • Check the return value of dlopen() before using the library handle.
  • Use dlerror() immediately after runtime loading failures.
  • Export only stable public APIs.
  • Maintain binary compatibility across library versions whenever possible.
  • Release library handles with dlclose().

36. Common Programming Mistakes

  • Forgetting to compile shared libraries using -fPIC.
  • Ignoring errors returned by dlopen().
  • Casting function pointers incorrectly after dlsym().
  • Assuming every library update is binary compatible.
  • Using incorrect runtime library search paths.
  • Forgetting to release dynamically loaded libraries.

37. Advanced Interview Questions

  1. Why are shared libraries preferred over static libraries in modern operating systems?
  2. Explain Position Independent Code (PIC).
  3. How does dlopen() differ from normal dynamic linking?
  4. Why is dlsym() required after calling dlopen()?
  5. What is binary compatibility?
  6. Why should shared libraries expose only required symbols?
  7. How does the dynamic loader resolve external symbols?
  8. Which command displays the dynamic dependencies of an executable?
  9. Why is dlerror() important for debugging?
  10. How are plug-in architectures implemented using shared libraries?

38. Module Summary

This module introduced shared libraries and dynamic linking in UNIX systems. We studied static and shared libraries, Position Independent Code, dynamic loading using dlopen(), dlsym(), dlerror(), and dlclose(), library creation, runtime linking, library inspection tools, development workflow, best practices, and common programming mistakes. Shared libraries are fundamental to modern UNIX software because they reduce executable size, improve memory utilization, simplify software maintenance, and enable modular application design through runtime loading.

Knowledge Check

Concept Mastery Assessment — Module 38

Verify your conceptual understanding with 12 targeted technical assessment questions. Instant feedback and explanations are provided for every choice.

Question 1 of 12
What is the primary architectural purpose of Shared Libraries, Dynamic Linking & dlopen in operating systems?
Explanation
Shared Libraries, Dynamic Linking & dlopen is designed to manage position-independent code (pic), global offset table (got), procedure linkage table (plt), ld.so dynamic linker, and runtime loading with dlopen/dlsym. within the operating system architecture.
Question 2 of 12
Which system interface or data structure is centrally associated with Shared Libraries, Dynamic Linking & dlopen?
Explanation
Under POSIX and Linux, Shared Libraries, Dynamic Linking & dlopen operates through standardized system calls and kernel control structures.
Question 3 of 12
What safety or concurrency constraint must developers consider when implementing Shared Libraries, Dynamic Linking & dlopen?
Explanation
Proper synchronization, avoidance of race conditions, and handling reentrant execution are critical when working with Shared Libraries, Dynamic Linking & dlopen.
Question 4 of 12
When a system call related to Shared Libraries, Dynamic Linking & dlopen fails in C, how does the POSIX runtime conventionally report the failure?
Explanation
Standard POSIX system calls return -1 or NULL on error, assigning an error integer (e.g. EINVAL, EPERM, EAGAIN) to the thread-local errno variable.
Question 5 of 12
What is the primary performance tradeoff associated with Shared Libraries, Dynamic Linking & dlopen?
Explanation
Operations involving Shared Libraries, Dynamic Linking & dlopen balance performance against kernel transition, memory bandwidth, and cache locality tradeoffs.
Question 6 of 12
What security principle governs access to resources in Shared Libraries, Dynamic Linking & dlopen?
Explanation
The kernel validates credentials, effective permissions, and Linux capabilities before granting access to protected operations.
Question 7 of 12
How does execution of Shared Libraries, Dynamic Linking & dlopen transition between User Space and Kernel Space?
Explanation
User space transitions to kernel mode securely via software traps or SYSCALL instructions that switch processor rings to Ring 0.
Question 8 of 12
What happens to resources allocated by Shared Libraries, Dynamic Linking & dlopen when the owning process terminates?
Explanation
Process resources (open fds, memory maps) are automatically reclaimed by the kernel on termination, while kernel-persistent objects survive.
Question 9 of 12
In production Linux server environments, how is Shared Libraries, Dynamic Linking & dlopen optimized for high throughput?
Explanation
Linux optimizes throughput via zero-copy data paths, asynchronous kernel events, and scalable concurrency primitives.
Question 10 of 12
What standard governs the portability of Shared Libraries, Dynamic Linking & dlopen across Unix, Linux, and macOS platforms?
Explanation
IEEE POSIX standards define consistent APIs across Unix-like platforms ensuring portable source code execution.
Question 11 of 12
Which command-line diagnostic tool is most effective for inspecting and troubleshooting Shared Libraries, Dynamic Linking & dlopen at runtime?
Explanation
Utilities like strace, lsof, and the /proc filesystem provide direct visibility into kernel interactions and resource status.
Question 12 of 12
What is a critical production best practice when developing systems software involving Shared Libraries, Dynamic Linking & dlopen?
Explanation
Defensive programming requires explicit error checking on all system operations, proper resource cleanup, and avoiding memory corruption.
0 / 12 (0%)
Great job! Review the concepts above and proceed when ready.
ADVERTISEMENT
Responsive Ad Unit • Technical Courses & Certifications