SuperAPI AI 工具集

dynamic-linking

编程与开发

查看项目

更新于 10-15 15:12

技能介绍

用途

Dynamic Linking 技能用于指导智能体处理 Linux 上 ELF 共享库的动态链接相关问题,覆盖共享库创建、库加载失败排查、RPATH 与 RUNPATH 配置、soname 版本管理、dlopen/dlsym 插件模式、LD_PRELOAD 函数拦截以及符号可见性控制。

它适用于诸如以下触发场景:

  • “Cannot open shared object file: No such file or directory”
  • 如何设置 RPATH 让二进制找到共享库
  • 如何使用 dlopen/dlsym 构建插件系统
  • RPATH 与 RUNPATH 的区别
  • 如何使用 LD_PRELOAD 拦截函数
  • 如何用 soname 为共享库做版本管理

主要能力

创建共享库

使用 -fPIC 编译位置无关代码,使用 -shared 链接共享库,并通过 -Wl,-soname 指定 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
ln -s libmylib.so.1     libmylib.so
sudo cp libmylib.so.1.2.3 /usr/local/lib/
sudo ldconfig

其中 libmylib.so.1 为 soname 链接(供 ldconfig 使用),libmylib.so 为链接链接(编译时使用)。

soname 版本约定

命名格式为 libfoo.so.MAJOR.MINOR.PATCH,soname 为 libfoo.so.MAJOR。版本递增规则:PATCH 用于缺陷修复且 ABI 不变;MINOR 用于新增符号且向后兼容;MAJOR 用于 ABI 破坏,现有二进制会失效。可用 readelf -d 或 objdump -p 检查 SONAME。

RPATH 与 RUNPATH

两者都会在二进制中嵌入库搜索路径。RPATH 在 LD_LIBRARY_PATH 之前搜索,RUNPATH 在其之后搜索(可在运行时控制)。技能建议优先使用 RUNPATH(-Wl,--enable-new-dtags)以获得部署灵活性。可通过 readelf -d 检查,也可用 chrpath -l 查看、chrpath -r 修改。$ORIGIN 在运行时解析为二进制所在目录,适合可重定位安装。

库搜索顺序

  1. DT_RPATH(在不存在 DT_RUNPATH 时)
  2. LD_LIBRARY_PATH(环境变量,对 suid 二进制无效)
  3. DT_RUNPATH
  4. /etc/ld.so.cache(由 ldconfig 依据 /etc/ld.so.conf 生成)
  5. /lib、/usr/lib

可用 LD_DEBUG=libs 跟踪加载决策,用 ldd 或 ldd -v 查看解析结果与版本要求。

dlopen/dlsym 插件模式

技能给出插件加载示例,涉及 RTLD_NOW(立即解析全部符号,快速失败)、RTLD_LAZY(首次调用时解析)、RTLD_LOCAL(符号不对外可见)、RTLD_GLOBAL(符号全局可见)等标志,并强调在 dlsym 前调用 dlerror() 清除此前错误,加载失败时输出 dlerror() 信息,最后 dlclose 释放。编译时需链接 -ldl。

LD_PRELOAD 拦截

LD_PRELOAD 会在其他库之前加载指定库,其符号覆盖应用程序的符号。技能以拦截 malloc 为例,通过 dlsym(RTLD_NEXT, "malloc") 找到调用链中的下一个 malloc,编译为共享库后通过 LD_PRELOAD=./myinterpose.so 应用于任意二进制。

符号可见性控制

可通过 attribute((visibility("default"))) 标记对外可见符号,用 visibility("hidden") 隐藏内部符号;也可使用链接器版本脚本(如 mylib.map)仅导出指定符号、隐藏其余符号。技能建议默认使用 -fvisibility=hidden 编译并显式标记公共 API,可用 nm -D --defined-only 或 objdump -T 检查导出符号。

常见错误

技能列出若干常见错误及原因与修复方向:

  • cannot open shared object file:库不在搜索路径中,可设置 RPATH、LD_LIBRARY_PATH 或运行 ldconfig。
  • symbol lookup error: undefined symbol:缺库或版本错误,可检查 ldd、补充 -l 参数或修正链接顺序。
  • FATAL: kernel too old:版本要求不匹配,需针对较旧 glibc 重新构建。
  • relocation R_X86_64_32 against .rodata:共享库中存在非 PIC 代码,编译时需添加 -fPIC。
  • version 'GLIBC_2.29' not found:二进制在更新的 glibc 上构建,需在较旧系统上重建或使用 -static。

使用方式

技能以工作流形式组织,涵盖从创建共享库、版本管理、路径配置、搜索顺序调试、插件加载、函数拦截到符号可见性控制的完整流程,并附带命令与代码示例。关于 RPATH、soname 与 ld.so 配置的更多细节,技能指向 references/ld-rpath-soname.md。

适用场景

适合需要排查或设计 Linux 动态链接行为的开发与调试场景,包括共享库部署、可重定位安装、插件架构、运行时函数拦截和符号导出管理。

限制

该技能聚焦 Linux/ELF 动态链接。资料中未提供其他平台的说明,也未提及收费、价格或平台支持范围等额外信息。