dlclose()无法卸载链接到boost的.so文件 [英] dlclose() not unloading .so-file which is linking to boost

查看:210
本文介绍了dlclose()无法卸载链接到boost的.so文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我的应用程序加载(使用dlopen)链接到Boost Test Framework的.so文件,则无法卸载so文件.如果不进行链接以增强效果,则将其卸载似乎很好.

If my app loads (using dlopen) a .so file, that is linking to the Boost Test Framework, I can't unload the so file. Without linking to boost it seems to be fine to unload it.

应用文件main.cpp:

App file main.cpp:

#include <dlfcn.h>
#include <iostream>

int main()
{
   auto sFileName = "./libtest_library.so";
   auto handle = dlopen(sFileName, RTLD_LAZY | RTLD_LOCAL);

   if (!handle) 
      std::cerr << "Error: " << dlerror() << std::endl;

   auto closing = dlclose(handle);
   while(1);
   return 0;
}

库.so文件(libtest_library.so):

Library .so file (libtest_library.so):

#include <iostream>
//#include "boost/test/unit_test.hpp"

static void con() __attribute__((constructor));
static void dcon() __attribute__((destructor));

void con()
{
   std::cout << "Constructing library..." << std::endl;
}

void dcon()
{
   std::cout << "Destructing library..." << std::endl;
}

运行此命令,我得到输出:

Running this I get the output:

Constructing library...
Destructing library...

如果我在libtest_library.link中链接到Boost的单元测试框架,那么我只会得到Constructing library...输出. dlclose(handle)返回0(成功).

If I link to Boost's unit test framework in libtest_library.so I only get the Constructing library... output. dlclose(handle) returns 0 (which is success).

当前与Boost v.1.60.0链接,在Ubuntu 14.04上使用gcc 5_2_0进行编译. 这是Boost中的错误吗?编译器?有任何想法吗?

Currently linking against Boost v. 1.60.0, compiling with gcc 5_2_0 on Ubuntu 14.04. Is this a bug in Boost? Compiler? Any ideas?

我需要在项目中多次重载.so文件,并且需要将其完全卸载(内存中不存在).我该如何解决?谢谢.

I need to reload the .so files several times in a project, and it needs to be fully unloaded (not existing in the memory). How can I solve this? Thanks.

更新1:
似乎如果我仅链接到boost的libtest_library析构函数实际上是被调用的,但是boost_test_framework库没有被卸载.但是,如果我包含"boost/test/unit_test.hpp",则不会调用该析构函数(libtest_library.so拒绝卸载).

Update 1:
It seems like if I only link to boost the libtest_library destructor is actually called but the boost_test_framework library is not unloaded. However, if I include "boost/test/unit_test.hpp", the destructor won't be called (libtest_library.so refuse to unload).

更新2:
通过查看boost的来源,我发现boost中有一个c ++单例会导致问题.

Update 2:
Looking through boost's sources I’ve found that there is a c++ singleton in boost causing the problem.

我可以用简化版本来复制问题. 基本上,如果我将以下单例添加到libtest_library中,它将不起作用(无法卸载.so文件):

I can replicate the problem in a simplified version. Basically if I add the following singleton to the libtest_library it doesn’t work (can’t unload the .so file):

替代1

class Singleton
{
public:
   static Singleton & getInstance() { static Singleton instance; return instance; }    
private:
   Singleton() {}
   ~Singleton() {}
};

static Singleton & singleton = Singleton::getInstance();

但是使用此方法有效:

替代2

class Singleton
{
public:
    static Singleton & getInstance();
private:
   Singleton() {}
   ~Singleton() {}
};

Singleton & Singleton::getInstance() { static Singleton instance; return instance; }

static Singleton & singleton = Singleton::getInstance();

我尝试了不同的GCC编译器,但结果相同.对我来说,这似乎是个虫子?

I’ve tried the different GCC compilers and it leads to the same results. For me this seems to be bug?

符号也有所不同:nm –C libtest_library.so | grep –i singleton我明白了

Also the symbols are a bit different: doing nm –C libtest_library.so | grep –i singleton I get

替代项1(无效):

0000000000201460 u guard variable for Singleton::getInstance()::instance
0000000000201458 b singleton
0000000000000e66 W Singleton::getInstance()
0000000000000f08 W Singleton::Singleton()
0000000000000f08 W Singleton::Singleton()
0000000000000f1c W Singleton::~Singleton()
0000000000000f1c W Singleton::~Singleton()
0000000000201468 u Singleton::getInstance()::instance

和替代2:

00000000002012f8 b guard variable for Singleton::getInstance()::instance
0000000000201300 b singleton
0000000000000bb0 T Singleton::getInstance()
0000000000000cec W Singleton::Singleton()
0000000000000cec W Singleton::Singleton()
0000000000000d00 W Singleton::~Singleton()
0000000000000d00 W Singleton::~Singleton()
0000000000201308 b Singleton::getInstance()::instance

有什么想法吗?

更新3

我已经提取了boost中似乎会造成问题的部分,并创建了一个演示该问题的最小示例:

I've extracted out the part in boost that seems to create the problem and created a minimal example that demonstrate the problem:

main_app.cpp -主应用

#include <dlfcn.h>
#include <iostream>

int main()
{
   for(auto i = 0; i < 2; i++) {
      auto sFileName = "./libtest_library.so";
      auto handle = dlopen(sFileName, RTLD_LAZY | RTLD_LOCAL);

      if (!handle) {
         printf("Dlerror: %s\n", dlerror());
         continue;
      }

      auto closing = dlclose(handle);
      printf("Dlerror: %s\n", dlerror());
   }

   return 0;
}

main_lib.cpp -libtest_library.so

main_lib.cpp - libtest_library.so

#include <iostream>

template<typename Derived>
class trivial_singleton_t {
public:
   static Derived& instance() { static Derived the_inst; return the_inst; }
protected:
   trivial_singleton_t() {}
   ~trivial_singleton_t() {}
};

class singleton_t : public trivial_singleton_t<singleton_t> {

private:
   friend class trivial_singleton_t<singleton_t>;
   singleton_t() {}
};

singleton_t & singleton = singleton_t::instance();

static void con() __attribute__((constructor));
static void dcon() __attribute__((destructor));

void con()
{
   std::cout << "Constructing library..." << std::endl;
}

void dcon()
{
   std::cout << "Destructing library..." << std::endl;
}

我得到以下输出:

Constructing library...
Dlerror: (null)
DLerror: (null)
Destructing library...

因此,仅在main存在时才卸载该库.

hence the library is only unloaded when main exists.

推荐答案

问题中指出,已编译的二进制文件中有STB_GNU_UNIQUE个符号.

As noted in the question there are STB_GNU_UNIQUE symbols in the compiled binary files.

问题是正在使用这些符号并加载了dlopen的库将被标记为NODELETE,因此在dlopen/dlclose调用之间仍然存在.请参见此处的445行: http://osxr.org:8080/glibc/source/elf/dl-lookup.c

The problem is that a library that is using those symbols and loaded with dlopen will be flagged as NODELETE, and therefore persist between the dlopen/dlclose calls. See line 445 here: http://osxr.org:8080/glibc/source/elf/dl-lookup.c

https://sourceware.org/binutils/docs/binutils/nm.html STB_GNU_UNIQUEu:

该符号是唯一的全局符号.这是对ELF符号绑定的标准集合的GNU扩展.对于这样的符号,动态链接程序将确保在整个过程中只有一个使用此名称和类型的符号.

The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use.

当在匿名名称空间中创建变量/方法或将其作为静态全局变量创建这些变量时.

These are made when variables/methods are created within an anonymous namespace or as static global variables.

最快的解决方案是使用链接器标志--no-gnu-unique强制编译器不要将这些符号构建为STB_GNU_UNIQUE.

The quickest solution is to force the compiler to not build those symbols as STB_GNU_UNIQUE using a linker flag --no-gnu-unique.

不幸的是,这对我不起作用,因为我没有足够新的链接程序,幸运的是,我可以使用以下配置选项来重建gcc:--disable-gnu-unique-object.记住也要使用链接器标记或新的gcc重建boost库.

Unfortunately this didn't work for me since I didn't have a sufficiently recent linker, luckily I could rebuild gcc with the following configuration option: --disable-gnu-unique-object. Remember to also rebuild the boost library using the linker flag or new gcc.

这篇关于dlclose()无法卸载链接到boost的.so文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆