К основному содержанию
скилл CX Codex

dynamic-linking — скилл для Claude Code: динамические библиотеки Linux

Скилл для работы с динамической линковкой в Linux: разбирает ошибки загрузки .so, настройку RPATH и RUNPATH, версионирование soname.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add mohitmishra786/low-level-dev-skills --skill dynamic-linking -a claude-code
Открыть на GitHub

Что делает dynamic-linking

Скилл ведёт агента по динамической линковке в Linux: сборка разделяемых библиотек, конфигурация RPATH и RUNPATH, версионирование soname, плагины через dlopen/dlsym, перехват функций через LD_PRELOAD и управление видимостью символов. Активируется сам, когда в запросе всплывают cannot open shared object file, LD_LIBRARY_PATH, soname или вопросы про порядок поиска библиотек.

Внутри — восемь разделов с командами и кодом. Сборка библиотеки через gcc -fPIC и -shared с soname, таблица версий (PATCH, MINOR, MAJOR), разница между RPATH и RUNPATH с рекомендацией в пользу RUNPATH для гибкости при развёртывании, порядок поиска от DT_RPATH до /lib и /usr/lib. Отладка через LD_DEBUG=libs и ldd -v. Есть шаблон плагина на C с RTLD_NOW и RTLD_LOCAL, пример перехвата malloc через dlsym(RTLD_NEXT, ...) и version script для скрытия внутренних символов.

Для работы нужен компилятор GCC и утилиты readelf, objdump, chrpath, nm. Плагины линкуются с -ldl. Если бинарник собран на новой glibc, на старой системе он упадёт с version 'GLIBC_2.29' not found — это повод проверить, где именно вы собираете релиз.

Какие задачи решает

  • разобраться, почему бинарник не находит свою .so при запуске
  • выбрать между RPATH и RUNPATH для переносимой установки
  • собрать систему плагинов на dlopen и dlsym
  • перехватить вызов функции в чужом бинарнике через LD_PRELOAD
  • скрыть внутренние символы библиотеки, чтобы не было конфликтов

Примеры запросов агенту

  • почему мой бинарник падает с cannot open shared object file
  • как правильно выставить RPATH через $ORIGIN для переносимой сборки
  • покажи пример плагина на dlopen и dlsym с обработкой ошибок

Как установить dynamic-linking

1Через Skills CLI (Vercel)

npx skills add mohitmishra786/low-level-dev-skills --skill dynamic-linking -a claude-code

2Вручную: положить файлы

~/.claude/skills/dynamic-linking/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/dynamic-linking/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о dynamic-linking

Как установить dynamic-linking в Claude?

Выполните npx skills add mohitmishra786/low-level-dev-skills --skill dynamic-linking -a claude-code. Скилл появится в ~/.claude/skills/dynamic-linking/SKILL.md.

Что делает dynamic-linking?

Помогает агенту разбираться с динамической линковкой в Linux: сборка .so, soname, RPATH и RUNPATH, плагины на dlopen, перехват через LD_PRELOAD, видимость символов.

Чем RPATH отличается от RUNPATH?

RPATH ищется до LD_LIBRARY_PATH, RUNPATH — после, поэтому RUNPATH можно переопределить в рантайме. Скилл советует RUNPATH через -Wl,--enable-new-dtags.

Исходный текст

SKILL.md · MIT
---
name: dynamic-linking
description: 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.
---

# 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 soname
gcc -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 bump | When |
|-------------|------|
| PATCH | Bug fix, ABI unchanged |
| MINOR | New symbols added, backwards compatible |
| MAJOR | ABI break — existing binaries will break |

Inspect soname:

```bash
readelf -d libmylib.so.1.2.3 | grep SONAME
objdump -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_PATH
RUNPATH → 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

# Inspect
readelf -d myapp | grep -E 'RPATH|RUNPATH'
chrpath -l myapp        # show
chrpath -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_RUNPATH
4. /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 decisions
ldd myapp                  # show resolved libraries
ldd -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 binary
LD_PRELOAD=./myinterpose.so ./myapp
LD_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.map
MYLIB_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 symbols
nm -D --defined-only libmylib.so
objdump -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

| Error | Cause | Fix |
|-------|-------|-----|
| `cannot open shared object file` | Library not in search path | Set RPATH, `LD_LIBRARY_PATH`, or run `ldconfig` |
| `symbol lookup error: undefined symbol` | Missing library or wrong version | Check `ldd`, add `-l` flag or fix link order |
| `FATAL: kernel too old` | Version requirement mismatch | Rebuild against older glibc |
| `relocation R_X86_64_32 against .rodata` | Non-PIC code in shared lib | Add `-fPIC` to compilation |
| `version 'GLIBC_2.29' not found` | Binary built on newer glibc | Rebuild on older system or use `-static` |

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

## 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 · MIT · mohitmishra786/low-level-dev-skills

Похожие скиллы

Все скиллы по теме «Языки программирования» →
analyzing-linux-elf-malware mahipal Скилл для разбора подозрительных Linux-бинарников: статика, трассировка, дизассемблирование. Пригодится при разборе взломанного сервера или контейнера. CX Codex +1 457установок dwarf-expert trailofbits Разбирает отладочные секции DWARF в бинарниках, проверяет целостность деревьев DIE и помогает писать парсеры. Пригодится при анализе скомпилированного кода. CX Codex +1 5 200установок dali-dynamic-mode DALI Team Скилл ведёт агента по императивному режиму NVIDIA DALI: пишет вызовы ndd вместо графов пайплайнов и помогает переносить существующие пайплайны. CX Codex +1 2 100установок core-dynamic-skills actionbook Служебный скилл, который по зависимостям из Cargo.toml генерирует локальные скиллы для Rust-крейтов. Запускается только через команды синхронизации. CX Codex +1 1 800установок nextjs-dynamic-routes-params wsimmonds Скилл подсказывает агенту, как строить динамические сегменты App Router и читать params в Next.js 15+. Пригодится, когда страницы зависят от ID или слага из URL. CX Codex +1 303установок gke-ai-troubleshooting-tpu-dynamic-slices-monitoring официальный google Проверяет состояние TPU Dynamic Slices в GKE, помогает искать причины сбоев создания и сверяет манифесты одиночных и JobSet-нагрузок. CX Codex 3 700установок

Из того же набора62

heaptrack Ведёт агента по heaptrack: запись трасс аллокаций, разбор через heaptrack_print, поиск утечек и сравнение запусков. CX Codex +1 623установок msvc-cl Подсказывает агенту, как компилировать C и C++ через MSVC cl.exe и clang-cl: флаги, рантайм, PDB, ошибки линковки. CX Codex +1 617установок linkers-lto Скилл для настройки линкеров GNU ld, gold и lld, разбора ошибок порядка библиотек и включения LTO в реальных проектах. CX Codex +1 608установок binutils Скилл для работы с бинарниками: статические библиотеки, strip, objcopy, addr2line, strings и c++filt. Пригодится, когда агент должен сам разобраться с постобработкой ELF. CX Codex +1 608установок rust-profiling Скилл для анализа производительности Rust: флеймграфы, размер бинарника, раздувание мономорфизации и микробенчмарки Criterion. CX Codex +1 586установок interpreters Подсказывает агенту, как устроить диспетчеризацию байткода, стековую или регистровую ВМ и простой JIT через mmap. CX Codex +1 564установок rust-ffi Ведёт агента по FFI между Rust и C: генерация биндингов через bindgen и cbindgen, безопасные обёртки, линковка системных библиотек. CX Codex +1 563установок meson Скилл для ИИ-агентов, который помогает настроить Meson, разобраться с wrap-зависимостями и кросс-компиляцией в C/C++ проектах. CX Codex +1 560установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой