본문으로 건너뛰기
cccskills
무료GitHub에 공개

dynamic-linking

Use when debugging shared library load failures, setting RPATH or RUNPATH, applying soname versioning, writing dlopen plugins, or intercepting with LD_PRELOAD. Not for static archives: use binutils.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(3)

  • SKILL.md7.3 KB
  • agents/openai.yaml228 B
  • references/ld-rpath-soname.md3.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Dynamic linking

Linux loads shared libraries at startup or on demand through ld.so. This skill builds versioned shared objects, places them where the loader finds them, and diagnoses the failures in between.

Contract

FieldBound contract
TriggerA build or run fails with cannot open shared object file or symbol lookup error, the task sets RPATH or RUNPATH, versions a library with a soname, writes a dlopen plugin, or interposes a function with LD_PRELOAD.
AuthorityReversible local: writes only built .so files, symlinks, source, and the loader cache entries the procedure names (ldconfig needs root); rollback is version control, removing created symlinks, and re-running ldconfig. No remote mutation.
Side effectLocal writes to build outputs, symlinks, and /etc/ld.so.cache when ldconfig runs. Environment variables and loader flags stay inside the session.
DoneThe binary runs against the intended library, proven by ldd resolving every dependency to the intended path and by a clean LD_DEBUG=libs trace or the plugin loading end to end.

Inputs

  • The failing binary or the library to build: required.
  • The intended library location: required for search-path work.
  • Whether deployment must be relocatable: required before choosing $ORIGIN, RPATH, or RUNPATH.
  • Root access: required only when registering a library system-wide with ldconfig.

Procedure

  1. Build the shared library with a soname. The soname is what executables record and what ldconfig maintains. Done when: readelf -d libmylib.so.1.2.3 prints the intended SONAME.
gcc -fPIC -c src/mylib.c -o mylib.o
gcc -shared -Wl,-soname,libmylib.so.1 mylib.o -o libmylib.so.1.2.3
ln -s libmylib.so.1.2.3 libmylib.so.1   # loader name
ln -s libmylib.so.1     libmylib.so     # linker name for -lmylib
  1. Bump versions by ABI change, not by habit. Done when: the bump class matches the change.
BumpWhen
PATCHBug fix, ABI unchanged
MINORSymbols added, backwards compatible: keep the soname, refresh the .so.1 symlink
MAJORABI breaks: new soname, old .so.1 files stay installed for existing binaries
  1. Embed the runtime search path. RPATH is searched before LD_LIBRARY_PATH; RUNPATH after it. Prefer RUNPATH for deployed binaries because environment variables then keep control. -Wl,--enable-new-dtags selects RUNPATH and is the modern linker default. $ORIGIN expands to the directory holding the binary, which makes an install tree relocatable. Done when: readelf -d myapp shows the intended tag and value.
gcc main.c -L./lib -lmylib \
    -Wl,-rpath,'$ORIGIN/../lib' -Wl,--enable-new-dtags -o myapp
readelf -d myapp | grep -E 'RPATH|RUNPATH'
chrpath -l myapp                 # show
chrpath -r '/new/path' myapp     # rewrite on an existing binary
  1. Know the search order to predict a failure. ld.so searches, in order: DT_RPATH when no DT_RUNPATH exists, then LD_LIBRARY_PATH (ignored for setuid binaries), then DT_RUNPATH, then the /etc/ld.so.cache built by ldconfig, then /lib and /usr/lib. Done when: the failing library is placed at a search step that the deployment controls.
LD_DEBUG=libs ./myapp   # trace each resolution decision
ldd -v ./myapp          # resolved paths plus version requirements
  1. Load a plugin with dlopen and dlsym. Clear dlerror() before each call; dlsym reports success through a null return from it, not from the pointer. Link with -ldl on glibc before 2.34; glibc 2.34 and later fold dlfcn into libc. Done when: the plugin loads, its entry point runs, and dlclose releases it.
#include <dlfcn.h>

typedef int (*plugin_fn_t)(const char *input);

void load_plugin(const char *path) {
    void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
    if (!handle) {
        fprintf(stderr, "dlopen: %s\n", dlerror());
        return;
    }
    dlerror();  // clear any error state before dlsym
    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);
}
  1. Interpose a function with LD_PRELOAD. The preloaded library is searched first, so its symbols win. RTLD_NEXT finds the next definition in the chain. Done when: running with LD_PRELOAD=... shows the interception and the real call still works.
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

void *malloc(size_t size) {
    static void *(*real_malloc)(size_t) = NULL;
    if (!real_malloc)
        real_malloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc");
    void *ptr = real_malloc(size);
    fprintf(stderr, "malloc(%zu) = %p\n", size, ptr);
    return ptr;
}
gcc -shared -fPIC -o myinterpose.so myinterpose.c -ldl
LD_PRELOAD=./myinterpose.so ./myapp
  1. Export only the intended symbols. Build with -fvisibility=hidden and mark the public API visibility("default"), or restrict exports with a version script. Done when: nm -D --defined-only libmylib.so lists the public API and nothing else.
__attribute__((visibility("default"))) int public_api(void) { return 42; }
# mylib.map
MYLIB_1.0 {
    global:
        mylib_init;
        mylib_process;
    local:
        *;
};
gcc -shared -fPIC -fvisibility=hidden -Wl,--version-script=mylib.map \
    mylib.c -o libmylib.so
  1. Diagnose the common failures. Done when: each reported error maps to its row and the fix is applied.
ErrorCauseFix
cannot open shared object fileLibrary outside the search pathSet RUNPATH, extend LD_LIBRARY_PATH, or run ldconfig
symbol lookup error: undefined symbolMissing library or version mismatchCheck ldd, fix link order, or add the missing -l
relocation R_X86_64_32 against .rodataNon-PIC code in a shared objectCompile that object with -fPIC
version 'GLIBC_2.xx' not foundBuilt on a newer glibc than the runtimeBuild on the older host or link statically

Failure and recovery

Failure classBehavior
ldd shows not found after a correct RUNPATHThe dependency of a dependency needs its own RUNPATH. Trace with LD_DEBUG=libs and fix the library that records the path.
chrpath refuses a longer pathchrpath cannot grow an existing string. Rebuild with the correct -Wl,-rpath, or use patchelf --set-rpath.
Interposition breaks a setuid binaryThe loader ignores LD_PRELOAD and LD_LIBRARY_PATH for setuid executables. This is loader policy, not a bug.
Plugin symbols clash across librariesReopen the plugin with RTLD_LOCAL, or hide symbols per step 7.
ldconfig not runnableRoot is required. Ship the RUNPATH inside the binary instead, and skip the system-wide registration.

Output

The running binary or loaded plugin, plus the resolving evidence: ldd output, the SONAME and RUNPATH lines from readelf -d, or the interposition trace. Deep details on search paths, $ORIGIN, and version scripts are in references/ld-rpath-soname.md.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Use when explaining System V AMD64, ARM AAPCS, RISC-V psABI, stack frames, variadic calls, or FFI register rules. Not for the Rust FFI binding layer: use rust-ffi.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

Use when configuring ADC sampling time, DMA-driven ADC, calibration, or DAC channel setup on bare-metal MCUs. Not for the DMA stream itself: use dma-baremetal.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

af-xdp

무료

Use when creating AF_XDP sockets, configuring UMEM and XSK rings, writing an XDP redirect program, or choosing copy versus zero-copy mode. Not for full kernel bypass: use dpdk.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

Use when a completed session needs an agent-environment retrospective. Not for an engineering retrospective from telemetry: use engineering-retrospective.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

Use when a redacted, trimmed agent transcript must be appended to a GitHub PR or issue body, with human approval and preview. Not for automated or model-initiated insertion.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

agents-md

무료

Use when a repo needs agent setup, AGENTS.md added or made lean, CLAUDE.md audited, or agent instructions scored or pruned. Not for remote, credential, publish, deploy, or irreversible changes.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

OutlineDriven/odin-claude-plugin372026년 9월 29일 업데이트

OutlineDriven의 스킬 모두 보기

이 스킬의 문제 신고