使用`dlopen`重新加载运行时库

6
一个正在运行的基于C++的进程是否可以使用dlopen重新加载基于C++的动态库?
正在运行的进程轮询新版本的动态库(具有相同的API)。 一旦检测到这样的文件,将执行以下一系列操作:
  1. 使用dlclose卸载旧库。
  2. 复制新的dylib并覆盖旧版本的文件。
  3. 使用dlopen从该位置加载更新的版本。
  4. 根据新加载的库中的dlsym设置函数指针变量。
在最后阶段,我实际上获得所需的API并将其放置在主代码中的函数指针中以供以后使用。
然而,似乎我的程序在第三阶段意外崩溃了。 是否可能dlclose部分在进程虚拟空间中留下旧库的残留物? 有更好的方法吗?
顺便说一下,在Windows上,使用LoadLibrary,FreeLibrary和GetProcAddress而不是dlopen,dlclose和dlsym可以正常工作。

但是如果我仍然想重新加载新的库版本,我可以通过更改文件名来实现吗?例如,在后缀之后添加其版本号? - Zohar81
是的,但你的问题可能是你没有重新加载从dlsym获取的函数和对象。 - Quentin
@Quentin,我实际上是使用dlsym获取我需要的API(请参见更新的问题),难道链接器不会混淆具有相同名称的旧符号吗? - Zohar81
1个回答

5
似乎我的程序在第三阶段后意外崩溃了。有可能是dlclose部分在进程虚拟空间中留下了旧库的残留物吗?
这是可能的。指向库中定义的函数的函数指针对象和定义了虚函数的对象将以无效指针结束。更糟糕的是,可以将新facet附加到标准流(例如std::cout),然后卸载实现facet的共享库。稍后在不相关的地方使用std::cout时会崩溃(真实故事)。因此,您必须完全控制共享库所做的所有操作。
此外,必须使用RTLD_LOCAL调用dlopen,以便没有其他内容可以(意外地)使用正在加载的共享库的符号并防止其卸载。如果您执行此类操作,则必须阅读并理解man dlopen

2
GCC也可能会输出唯一符号,即使使用了RTLD_LOCAL,这些符号也可以防止卸载。在使用nm时,它们显示为u。最常见的情况是在inline函数和/或函数模板中的static变量中。我们在仅包含头文件的库(例如Boost的某些部分)中遇到了这个问题,但我的同事们也设法创建了这些符号。问题在于,如果插件是第一个引入它们的DSO,它就永远无法被卸载。dlclose成功了,但二进制文件仍然保持映射状态。 - Arne Vogel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接