Dynamic Linking

mohitmishra786/low-level-dev-skills/skills/binaries/dynamic-linking

作者 mohitmishra786bdc58472fa9f无许可证253 个星标收录于 2026年10月9日更新于 2026年10月9日仓库3个月前更新

Dynamic linking skill for Linux/ELF shared libraries. Use when debugging library loading failures, configuring RPATH vs RUNPATH, understanding soname versioning, using dlopen/dlsym for plugin systems, LD_PRELOAD interposition, or controlling symbol visibility. Activates on queries about shared libraries, dlopen, LD_LIBRARY_PATH, RPATH, soname, LD_PRELOAD, symbol visibility, or "cannot open shared object file" errors.

AI 生成的概览

指导代理处理 Linux ELF 动态链接:共享库、RPATH/RUNPATH、soname、dlopen 插件、LD_PRELOAD 与符号可见性。

功能
提供创建和配置 Linux 共享库的参考说明,涵盖 -fPIC 编译、soname 版本约定、RPATH 与 RUNPATH 的搜索顺序以及 ldconfig 注册。还说明 dlopen/dlsym 插件加载、LD_PRELOAD 函数拦截、通过属性和版本脚本控制符号可见性,并给出常见加载错误及修复方法的对照表。产出为指导内容和命令示例,而非文件。
适用场景
适用于排查库加载失败(如“cannot open shared object file”),或配置 RPATH/RUNPATH、soname 版本、基于 dlopen 的插件系统、LD_PRELOAD 拦截和符号可见性。面向 Linux/ELF 共享库相关工作。
运行要求
该技能不附带脚本,仅为说明性内容。按其指导操作需要 Linux 环境及工具链和检查工具,如 gcc、ld、readelf、objdump、nm、ldd、chrpath 和 ldconfig,dlopen 示例还需要 libdl 库。

Dynamic Linking

Purpose

Guide agents through Linux dynamic linking: shared library creation, RPATH/RUNPATH configuration, soname versioning, dlopen/dlsym plugin patterns, LD_PRELOAD interposition, and symbol visibility control.

Triggers

  • "Cannot open shared object file: No such file or directory"
  • "How do I set RPATH so my binary finds its shared library?"
  • "How do I use dlopen/dlsym for a plugin system?"
  • "What's the difference between RPATH and RUNPATH?"
  • "How do I use LD_PRELOAD to intercept a function?"
  • "How do I version my shared library with soname?"

Workflow

1. Creating a shared library

bash
# Compile with -fPIC (position-independent code)gcc -fPIC -c src/mylib.c -o mylib.o
# Link shared library with sonamegcc -shared -Wl,-soname,libmylib.so.1 \    mylib.o -o libmylib.so.1.2.3
# Create symlinks (standard convention)ln -s libmylib.so.1.2.3 libmylib.so.1   # soname link (used by ldconfig)ln -s libmylib.so.1     libmylib.so      # link link (used at compile time)
# Register with ldconfig (system-wide)sudo cp libmylib.so.1.2.3 /usr/local/lib/sudo ldconfig

2. Soname versioning convention

text
libfoo.so.MAJOR.MINOR.PATCH         │         └── soname = libfoo.so.MAJOR
Version bumpWhen
PATCHBug fix, ABI unchanged
MINORNew symbols added, backwards compatible
MAJORABI break — existing binaries will break

Inspect soname:

bash
readelf -d libmylib.so.1.2.3 | grep SONAMEobjdump -p libmylib.so.1.2.3 | grep SONAME

3. RPATH vs RUNPATH

text
Both embed a library search path in the binary.
RPATH  → searched BEFORE LD_LIBRARY_PATHRUNPATH → searched AFTER LD_LIBRARY_PATH (controllable at runtime)
Recommendation: prefer RUNPATH (-Wl,--enable-new-dtags)                for deployment flexibility.
bash
# Embed RPATH (old default)gcc main.c -L./lib -lmylib \    -Wl,-rpath,'$ORIGIN/../lib' -o myapp
# Embed RUNPATH (new default with --enable-new-dtags)gcc main.c -L./lib -lmylib \    -Wl,-rpath,'$ORIGIN/../lib' \    -Wl,--enable-new-dtags -o myapp
# Inspectreadelf -d myapp | grep -E 'RPATH|RUNPATH'chrpath -l myapp        # showchrpath -r '/new/path' myapp  # modify existing

$ORIGIN resolves to the directory of the binary at runtime — use it for relocatable installations.

4. Library search order

text
1. DT_RPATH (if no DT_RUNPATH present)2. LD_LIBRARY_PATH (env var, ignored for suid binaries)3. DT_RUNPATH4. /etc/ld.so.cache  (populated by ldconfig from /etc/ld.so.conf)5. /lib, /usr/lib

Debug with:

bash
LD_DEBUG=libs ./myapp      # trace library loading decisionsldd myapp                  # show resolved librariesldd -v myapp               # verbose with version requirements

5. dlopen / dlsym plugin pattern

c
#include <dlfcn.h>
typedef int (*plugin_fn_t)(const char *input);
void load_plugin(const char *path) {    // RTLD_NOW: resolve all symbols immediately (fail fast)    // RTLD_LAZY: resolve on first call (default)    // RTLD_LOCAL: symbols not visible to other loaded libs    // RTLD_GLOBAL: symbols visible globally    void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);    if (!handle) {        fprintf(stderr, "dlopen: %s\n", dlerror());        return;    }
    // Clear previous errors    dlerror();
    plugin_fn_t fn = (plugin_fn_t)dlsym(handle, "plugin_run");    const char *err = dlerror();    if (err) {        fprintf(stderr, "dlsym: %s\n", err);        dlclose(handle);        return;    }
    fn("hello");    dlclose(handle);}

Link with -ldl:

bash
gcc main.c -ldl -o myapp

6. LD_PRELOAD interposition

LD_PRELOAD loads a library before all others — its symbols override the application's.

c
// myinterpose.c — intercept malloc#define _GNU_SOURCE#include <stdio.h>#include <dlfcn.h>
void *malloc(size_t size) {    static void *(*real_malloc)(size_t) = NULL;    if (!real_malloc)        real_malloc = dlsym(RTLD_NEXT, "malloc");  // find next malloc in chain
    void *ptr = real_malloc(size);    fprintf(stderr, "malloc(%zu) = %p\n", size, ptr);    return ptr;}
bash
gcc -shared -fPIC -o myinterpose.so myinterpose.c -ldl
# Apply to any binaryLD_PRELOAD=./myinterpose.so ./myappLD_PRELOAD=/path/to/libfaketime.so ./myapp  # time manipulation

7. Symbol visibility control

Limit exported symbols to reduce binary size and avoid clashes:

c
// Mark default: visible to linker__attribute__((visibility("default")))int public_api(void) { return 42; }
// Hidden: internal, not exported__attribute__((visibility("hidden")))static int internal_helper(void) { return 0; }

Or use a linker version script:

text
# mylib.mapMYLIB_1.0 {    global:        mylib_init;        mylib_process;    local:        *;          # hide everything else};
bash
gcc -shared -fPIC -Wl,--version-script=mylib.map \    -o libmylib.so mylib.c
# Check exported symbolsnm -D --defined-only libmylib.soobjdump -T libmylib.so

Build with -fvisibility=hidden by default and explicitly mark public API:

bash
gcc -shared -fPIC -fvisibility=hidden \    mylib.c -o libmylib.so

8. Common errors

ErrorCauseFix
cannot open shared object fileLibrary not in search pathSet RPATH, LD_LIBRARY_PATH, or run ldconfig
symbol lookup error: undefined symbolMissing library or wrong versionCheck ldd, add -l flag or fix link order
FATAL: kernel too oldVersion requirement mismatchRebuild against older glibc
relocation R_X86_64_32 against .rodataNon-PIC code in shared libAdd -fPIC to compilation
version 'GLIBC_2.29' not foundBinary built on newer glibcRebuild on older system or use -static

For RPATH, soname, and ld.so configuration details, see references/ld-rpath-soname.md [blocked].

Related skills

  • Use skills/binaries/elf-inspection to inspect shared library sections and symbols
  • Use skills/binaries/linkers-lto for linker flags and symbol resolution
  • Use skills/binaries/binutils for nm, objdump, strip on shared libs
  • Use skills/compilers/gcc for -fPIC, -shared and related compiler flags

来源与署名

来源:mohitmishra786/low-level-dev-skills位于skills/binaries/dynamic-linking提交bdc5847

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架