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 從公開儲存庫中收錄這些內容。

檢舉或申請下架