我使用的共享库有很多全局变量, 几乎用过 所有导出的函数都使库函数不是线程安全的。 我的应用程序创建多个线程,每个线程动态打开它 库并避免在并行调用之间使用任何同步 出口 函数,我用磁盘上的不同名称多次复制了库 每个线程都打开自己的副本。为了避免这种情况,现在我正在寻找使用dlmopen,但我遇到了一个问题。
当我在我的应用程序中使用dlopen打开库时,应用程序正常运行
libHandle = dlopen(ip->pathname, (RTLD_LAZY |RTLD_LOCAL|RTLD_DEEPBIND|RTLD_NODELETE));
当我在应用程序中使用dlmopen时,我收到错误:
ip->libHandle = dlmopen(LM_ID_NEWLM, ip->pathname,
(RTLD_LAZY |RTLD_LOCAL|RTLD_DEEPBIND|RTLD_NODELETE));
dlerror是:
error(libfoo.so.0: undefined symbol: _ZTIN6google8protobuf11MessageLiteE)
执行nm确实会显示未定义的符号 U _ZTIN6google8protobuf11MessageLiteE
问题1:我想知道如何解决此问题,以便我可以使用dlmopen。
原因是因为当使用LM_ID_NEWLM时,在libc中创建一个新的空命名空间而没有任何符号。因此,库应该是自包含的,或者与任何依赖项重新链接。
问题2:我的主应用程序导出一些libfoo将使用的符号。由于在新命名空间中打开libfoo,主应用程序的符号对libfoo不可见,因此无法解析它们。 有没有办法告诉链接器创建一个新的命名空间NEWLM,通过制作现有的基本命名空间的副本,而不是使用新创建的命名空间的dlmopen + lmid打开libfoo,其中所有其他必需的符号已经存在?
问题3:我自己可以对libfoo的不同部分进行mmap,并提供指向libc的mmaped部分的指针。意味着打开文件并将其从libc中删除并让它完成符号解析工作?这样我根本不需要调用dlopen,并且可以解决多文本部分问题。
答案 0 :(得分:3)
有没有办法告诉链接器创建一个新的命名空间NEWLM,通过制作现有的基本命名空间的副本,而不是使用新创建的命名空间的dlmopen + lmid打开libfoo,其中所有其他必需的符号已经存在?
以下是我解决类似问题的方法:
将protobuf动态加载到新的命名空间中:
void* pb_handle = dlmopen(LM_ID_NEWLM, "libprotobuf.so", RTLD_LAZY);
抓住名称空间ID:
Lmid_t lmid;
dlinfo(dl_handle, RTLD_DI_LMID, &lmid);
将foo打开到新的protobuf命名空间中:
void* foo_handle = dlmopen(lmid, “libfoo.so.0”, RTLD_LAZY);
答案 1 :(得分:2)
如何解决此问题
使用dlopen
时,新加载的库可以使用所有已加载的库来解析其符号。我猜测libprotobuf.so
是已经加载的库之一。
当您使用dlmopen(LM_ID_NEWLM, ...)
时,新加载的库必须完全自包含。
dlmopen
失败的事实告诉你它不是。您应该将libfoo.so.0
重新链接到libprotobuf.so
(以及它需要的任何其他库)。
使用ldd -r libfoo.so.0
验证其中的所有符号都已解析。在链接-Wl,--no-undefined
时使用libfoo.so.0
也是一个好主意。
<强>更新强>
我的主应用程序导出一些libfoo将使用的符号。由于在新命名空间中打开libfoo,主应用程序的符号对libfoo不可见,因此无法解析它们。
这是预期的行为。如果这些符号的数量相当少,您可以使用libfoo
void *h = dlmopen(...);
void (*init)(void *, void *) = dlsym(h, 'init');
(*init)(&main_fn1, &main_fn2);
有没有办法告诉链接器创建一个新的命名空间NEWLM,通过制作现有的基本命名空间的副本,而不是使用新创建的命名空间的dlmopen + lmid打开libfoo,其中所有其他必需的符号已经存在?
我不相信。这是一个有趣的想法。您可以在glibc bugzilla中打开功能请求。
使用dlmopen似乎是合理的(尽管最大限制为16)
在我看来,虽然libfoo
的16个实例优于1个,但在这条路径上你仍然受到严重限制,重写libfoo
以便不使用全局变量会好得多。第一名。
更新2:
我可以自己mmap libfoo的不同部分并提供指向libc的mmaped部分的指针
如果实施了GLIBC bug 11767,您可以。但事实并非如此。