LD_PRELOAD加载的共享库中,调用dlsym查找符号的最早可行时机
关于LD_PRELOAD库中dlsym查找依赖库符号的时机问题
最早成功的时间点
当通过LD_PRELOAD=buzz.so ./foo启动程序时,动态链接器会先完成所有必要共享库的加载与符号重定位——包括主程序foo直接链接的bar.so,以及bar.so的间接依赖库,之后才会执行任何构造函数。因此,buzz.so中能成功调用dlsym查找bar.so符号的最早时间点,就是buzz.so的构造函数执行阶段——哪怕是优先级最高的构造函数,此时bar.so已经被加载到进程地址空间,符号也已完成解析,dlsym调用必然成功。
如何在该时机执行函数
GCC/Clang的__constructor__属性可以指定构造函数的执行优先级,结合这个特性可以精准控制执行时机:
- 优先级数值范围为0到100,数值越小,构造函数执行越早;未指定优先级的构造函数默认使用100。
- 若无需等待其他库的构造函数,直接使用默认优先级即可:
#include <dlfcn.h> __attribute__((constructor)) void buzz_init() { // 查找bar.so中的目标符号,RTLD_DEFAULT搜索全局符号表 void (*bar_func)() = dlsym(RTLD_DEFAULT, "bar_target_function"); if (bar_func) { bar_func(); } } - 若需要确保在主程序或bar.so的构造函数之后执行(避免干扰其他初始化逻辑),可以将优先级设为大于100的数值(比如101):
__attribute__((constructor(101))) void buzz_late_init() { // 此处执行的逻辑会在默认优先级的构造函数之后运行 void *sym = dlsym(RTLD_DEFAULT, "bar_another_function"); // ... }
关键注意事项
- 编译buzz.so时必须链接dl库:添加
-ldl编译选项,否则dlsym、dlopen等函数会出现未定义引用错误。 - 若要更精准指定查找bar.so的符号,可以先用
dlopen("bar.so", RTLD_NOLOAD)获取bar.so的句柄(该选项不会重复加载库),再用此句柄调用dlsym,避免全局符号表的歧义。 - 即使bar.so使用延迟加载(
-z lazy),dlsym调用也会触发符号解析,不会影响查找结果。
内容的提问来源于stack exchange,提问作者Joseph Garvin
相关产品推荐
相关产品推荐

