调用dlmopen(LM_ID_NEWLM)时能否递归补全缺失的共享对象?
dlmopen(LM_ID_NEWLM)命名空间符号缺失问题解决方案 问题本质
LM_ID_NEWLM创建的新动态库命名空间是完全隔离的,默认不会继承父命名空间的任何已加载库与全局符号,因此未提前加载依赖的情况下直接加载目标so,必然会出现未定义符号报错。
可行方案(无需遍历/proc/$$/maps)
方案1:按需预加载目标so的依赖
你不需要导入当前进程关联的全部so,只需要提前加载目标so的直接依赖即可,操作轻量且可控:- 先用
ldd 你的目标.so查询所有依赖库列表 - 按依赖顺序加载到新命名空间,添加
RTLD_GLOBAL标志保证符号可被后续加载的库访问 - 首次创建命名空间后保存返回的命名空间ID,后续加载同命名空间的库直接使用该ID,不要重复传入
LM_ID_NEWLM
示例代码:
// 首次调用创建新命名空间,加载基础依赖 Lmid_t new_ns; void *libc_hdl = dlmopen(LM_ID_NEWLM, "libc.so.6", RTLD_LAZY | RTLD_GLOBAL); dlinfo(libc_hdl, RTLD_DI_LMID, &new_ns); // 保存新命名空间ID // 加载其他依赖 void *pthread_hdl = dlmopen(new_ns, "libpthread.so.0", RTLD_LAZY | RTLD_GLOBAL); // 最后加载目标so void *target_hdl = dlmopen(new_ns, "./你的目标.so", RTLD_LAZY);- 先用
方案2:直接加载主程序导出符号
如果你的目标so依赖主程序导出的自定义符号,可以直接在新命名空间加载主程序本身,一次性导入所有主程序导出的符号:void *main_hdl = dlmopen(LM_ID_NEWLM, "/proc/self/exe", RTLD_LAZY | RTLD_GLOBAL);方案3:高版本glibc继承全局符号
如果你使用glibc 2.39及以上版本,可以直接使用新增的命名空间扩展特性,指定新命名空间继承全局命名空间的所有符号,无需手动加载依赖。
不推荐遍历/proc/$$/maps的原因
全量导入进程所有已加载so会引入大量不必要的依赖,甚至会触发跨命名空间的符号冲突,同时/proc文件系统的格式在不同内核、发行版下存在细微差异,兼容性很差,非必要不要使用该方案。
内容的提问来源于stack exchange,提问作者KJ7LNW
相关产品推荐
相关产品推荐

