You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

共享库构造函数在dlopen加载时无法找到符号的问题排查

1. 编译时链接与运行时加载的差异

  • 编译时链接:
    • 链接器在编译阶段完成符号绑定,主程序与共享库的符号表会被合并处理。主程序的全局符号(如test)会被标记为可被共享库引用,链接器直接将共享库对test的引用绑定到主程序的对应符号地址。
    • 共享库的构造函数在程序启动、main执行前由加载器自动调用,此时整个进程的符号空间已完全初始化,共享库可直接访问主程序导出的符号。
  • 运行时加载(dlopen):
    • 共享库在程序运行到dlopen调用时才被加载到进程空间,符号绑定规则由dlopen参数和进程符号可见性规则决定。
    • 默认情况下,动态加载的共享库仅能从自身、已加载的其他共享库,以及全局符号表中查找未定义符号,而主程序的符号默认不会被加入全局符号表供动态加载的库引用。

2. 为什么dlopen无法找到test符号

核心原因是主程序的符号默认不对外暴露给动态加载的共享库:

  • 编译主程序时,编译器默认将主程序的符号标记为“局部”,即使添加__attribute__((used))也不会主动导出到进程的全局符号表。
  • dlopen加载liba.so时,构造函数so_init会被立即触发执行,此时它需要查找test符号,但主程序的test不在全局符号表中,因此触发“undefined symbol”错误。
  • 构造函数在dlopen返回前就会执行,后续手动绑定符号的操作根本来不及生效,必须在加载阶段就解决符号依赖。

3. 解决方法

有两种可靠的解决方案:

方案一:编译主程序时导出所有全局符号

编译主程序时添加-rdynamic参数,让主程序将所有全局符号导出到全局符号表,供动态加载的共享库使用。修改Makefile的test目标:

test:m.c
        $(CC) -fPIC -c m.c -o m.o
        $(CC) m.o -fPIC -o test -ldl -rdynamic

这样dlopen加载liba.so时,就能从全局符号表找到主程序的test符号,构造函数可正常调用。

方案二:显式指定dlopen的符号查找范围

调用dlopen时使用RTLD_LAZY | RTLD_GLOBAL参数,让加载的共享库可以访问主程序的符号(建议结合-rdynamic使用,确保符号可见性和查找范围都覆盖):

void* so = dlopen("./liba.so", RTLD_LAZY | RTLD_GLOBAL);

内容的提问来源于stack exchange,提问作者yhz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:39:46