Deep Dive into Linux Dynamic Linking: Building and Running .so Libraries
This article explains the fundamentals of Linux dynamic linking, compares .so shared objects with static libraries, walks through creating and compiling a simple math library, shows how to link and run an executable, and details runtime loading, library path configuration, and common troubleshooting techniques.
Dynamic linking and shared objects (.so)
In Linux, dynamic linking loads required libraries at program start‑up rather than embedding all code during compilation. A shared object file (.so) reduces binary size, enables independent updates, and allows multiple processes to share the same code in memory.
Building a .so library
Create the source file math_lib.c and its header math_lib.h:
// math_lib.c
#include "math_lib.h"
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
// math_lib.h
#ifndef MATH_LIB_H
#define MATH_LIB_H
int add(int a, int b);
int multiply(int a, int b);
#endifCompile the source into position‑independent code and create the shared object:
gcc -fPIC -c math_lib.c -o math_lib.o
gcc -shared -o libmath_lib.so math_lib.oThe two steps can be combined:
gcc -fPIC -shared -o libmath_lib.so math_lib.cLinking an executable with the .so
Write a program main.c that calls the library functions:
#include <stdio.h>
#include "math_lib.h"
int main() {
printf("5 + 3 = %d
", add(5, 3));
printf("5 * 3 = %d
", multiply(5, 3));
return 0;
}Compile while recording the dependency on libmath_lib.so: gcc main.c -I. -L. -lmath_lib -o main The resulting executable contains a NEEDED entry for libmath_lib.so but does not embed the library code.
Runtime library search and configuration
Running ./main triggers the dynamic linker to search for libmath_lib.so. If the library cannot be found, the error is:
error while loading shared libraries: libmath_lib.so: cannot open shared object file: No such file or directoryTypical solutions:
Copy the library to a system directory such as /usr/lib or /usr/local/lib (requires root).
Set the environment variable LD_LIBRARY_PATH to include the directory containing the .so, e.g. export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH.
Add a custom directory to /etc/ld.so.conf.d/ and run sudo ldconfig so the path is cached in /etc/ld.so.cache.
Embed an RPATH at link time with -Wl,-rpath,./ so the executable looks in the specified directory first.
The search order is: RPATH, LD_LIBRARY_PATH, /etc/ld.so.cache, then the default directories /lib and /usr/lib.
Manual loading of a shared library
Linux provides dlopen, dlsym, dlclose and dlerror in <dlfcn.h> for runtime loading:
#include <stdio.h>
#include <dlfcn.h>
int main() {
void *handle = dlopen("./libmath_lib.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "dlopen failed: %s
", dlerror());
return 1;
}
dlerror(); // clear any existing error
int (*add)(int,int) = (int (*)(int,int))dlsym(handle, "add");
const char *err = dlerror();
if (err) { fprintf(stderr, "dlsym add error: %s
", err); dlclose(handle); return 1; }
int (*multiply)(int,int) = (int (*)(int,int))dlsym(handle, "multiply");
if ((err = dlerror()) != NULL) { fprintf(stderr, "dlsym multiply error: %s
", err); dlclose(handle); return 1; }
printf("5 + 3 = %d
", add(5,3));
printf("5 * 3 = %d
", multiply(5,3));
if (dlclose(handle) != 0) {
fprintf(stderr, "dlclose error: %s
", dlerror());
return 1;
}
return 0;
}Compile the loader with the dynamic linking helper library:
gcc dynamic_load.c -ldl -o dynamic_loadCommon troubleshooting
Use ldd ./main to list the shared libraries required and see which ones are “not found”.
Check file permissions; the library must be readable by the executing user ( chmod a+r libmath_lib.so).
Verify that the library itself has all its dependencies satisfied ( ldd libmath_lib.so).
If a dependency such as libz.so is missing, install the appropriate package (e.g., sudo apt-get install zlib1g-dev on Ubuntu).
Re‑compile a clean library if the file is corrupted.
Link‑time dependency recording
When compiling main.c with gcc -o main main.c -L. -lmath_lib, the linker records a NEEDED entry for libmath_lib.so. The entry can be inspected with: readelf -d main The output contains a line like NEEDED Shared library: [libmath_lib.so], confirming the executable’s dependency.
Dynamic linker operation at runtime
At program start, the dynamic linker ( ld.so or ld-linux.so) searches the paths described above, loads the required .so files into memory, and binds the symbols (functions, variables) from the library to the references in the executable. For example, the calls to add and multiply in main are resolved to the actual addresses inside libmath_lib.so.
Library search path order
The dynamic linker follows this order:
RPATH embedded in the executable.
Directories listed in LD_LIBRARY_PATH.
Paths cached in /etc/ld.so.cache (generated by ldconfig).
Default system directories /lib and /usr/lib.
Explicit RPATH embedding
Embedding a runtime library search path removes the need for environment‑variable configuration:
gcc -o main main.c -L./ -lmath_lib -Wl,-rpath,./Dynamic loading example
The following program demonstrates explicit runtime loading using dlopen, dlsym and dlclose:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main() {
void *handle = dlopen("./libmath_lib.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "dlopen error: %s
", dlerror());
return 1;
}
dlerror(); // clear errors
int (*add)(int,int) = (int (*)(int,int))dlsym(handle, "add");
const char *err = dlerror();
if (err) { fprintf(stderr, "dlsym add error: %s
", err); dlclose(handle); return 1; }
int (*multiply)(int,int) = (int (*)(int,int))dlsym(handle, "multiply");
if ((err = dlerror()) != NULL) { fprintf(stderr, "dlsym multiply error: %s
", err); dlclose(handle); return 1; }
printf("5 + 3 = %d
", add(5,3));
printf("5 * 3 = %d
", multiply(5,3));
if (dlclose(handle) != 0) {
fprintf(stderr, "dlclose error: %s
", dlerror());
return 1;
}
return 0;
}Compile with: gcc dynamic_load.c -ldl -o dynamic_load Running ./dynamic_load prints the expected results, confirming successful manual loading.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Deepin Linux
Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
