linux 尽管dlclose,动态加载的库仍保持加载状态

xcitsw88  于 9个月前  发布在  Linux
关注(0)|答案(2)|浏览(142)

今天,我想了解一下动态加载器的神奇之处,我正在调试一个运行在Linux上的C++应用程序的插件系统,它通过dlopen(RTLD_NOW)加载插件|并使用dlclose发布它们。没有什么特别的-人们会认为。
然而,我注意到有些插件即使在dlclose被成功调用 * 之后仍然保持加载状态。我在使用pmap查看了正在运行的进程的内存Map后得出了这一结论。有些lib会立即从进程内存中删除,而其他lib则会无限期地徘徊。
接下来,dlopen man页面指出:
函数dlclose()减少动态库句柄句柄上的引用计数。如果引用计数下降到零,并且没有其他加载的库使用其中的符号,则动态库被卸载。
这意味着问题归结为两种可能性:要么引用计数不为零,要么其他加载的库使用了来自某些(但不是全部)插件的符号。
我很确定(虽然不是100%)引用计数为零。应用程序的插件管理器处理所有插件完全相同。它还确保插件不会多次加载。因此IMO加载和卸载应该对所有插件都一样。
这就剩下了第二种可能性:其他加载的lib使用了来自插件的符号。另一个典型的“这永远不应该发生”的情况。虽然这是肯定可能的。我们使用gcc和默认可见性,据我所知,没有任何东西被剥离,所以大量的符号被导出。实际上,这让我更担心,因为这些插件应该是独立的。
以下是我在这一点上的开放式问题:

  • 到目前为止,我的结论正确吗?
  • 你知道一种方法来验证dlopen的引用计数吗?
  • 如果我的插件的内部符号(意外地)被其他库使用,有没有办法追踪谁在使用哪些符号?

我的机器是:Linux 3.13.0-43-generic #72-Ubuntu SMP Mon Dec 8 19:35:44 UTC 2014 i686 i686 i686 GNU/Linux

  • 我应该提到的是,所有的加载和卸载都发生在主线程中,所以这里应该没有多线程问题。
wrrgggsh

wrrgggsh1#

其他加载的库使用插件中的符号
如果其他库在链接时未链接到该共享库,则引用共享库的符号不会阻止卸载该共享库。
要调试运行时链接器,请将环境变量LD_DEBUG设置为all,例如LD_DEBUG=all ./my_app。有关详细信息,请参阅man ld.so

vsmadaxz

vsmadaxz2#

很久以前你就发布了这个问题,你可能已经找到了答案,但它仍然可能对其他人感兴趣。我想说你的结论“其他加载的lib正在使用插件的符号”是正确的。系统能够在符号绑定时检测到这一点。glibc中的相关代码是AFAICT如下(glibc 2.38源代码中的elf/dl-lookup.c::_dl_lookup_symbol_x()):

/* We have to check whether this would bind UNDEF_MAP to an object
     in the global scope which was dynamically loaded.  In this case
     we have to prevent the latter from being unloaded unless the
     UNDEF_MAP object is also unloaded.  */
  if (__glibc_unlikely (current_value.m->l_type == lt_loaded)
      /* Don't do this for explicit lookups as opposed to implicit
         runtime lookups.  */
      && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
      /* Add UNDEF_MAP to the dependencies.  */
      && add_dependency (undef_map, current_value.m, flags) < 0)
    ...

字符串
这里值得注意的是对add_dependency()的调用。
换句话说,在符号查找时,会记录一个依赖项,这意味着如果其他库X使用了插件中的符号,那么只有当X被dlclosed时(这可能只发生在exit()),插件才会被卸载。
关于您的其他问题:
你知道一种方法来验证dlopen的引用计数吗?
我不知道该怎么做。
如果我的插件的内部符号(意外地)被其他库使用,有没有办法追踪谁在使用哪些符号?
LD_DEBUG=bindings应该可以帮助解决这个问题。

相关问题