Linux上的RTLD_LOCAL和dynamic_cast

时间:2011-05-19 15:13:20

标签: c++ linux dlopen

我们有一个插件,它由我们的应用程序中的一些共享库构成,我们需要在应用程序运行时更新它们。出于性能原因,我们在卸载旧插件之前加载并开始使用新插件,并且只有当使用旧插件完成所有线程时,我们才会卸载它。由于新插件的库和旧插件中的符号相同,我们dlopen()RTLD_LOCAL。如果我们没有新的插件从内部函数调用到旧插件的符号。

插件的一个库对由插件的另一个库创建的对象执行dynamic_cast()。这适用于HP-UX,AIX,Solaris和Windows,但不适用于Linux。据我所知,这是因为所有这些操作系统(编译器)都使用类的名称来比较类型(在dynamic_cast()中),但Linux使用名称字符串地址来进行此比较(以提高性能),因为每个库都有自己的type_info对象(因为它加载了RTLD_LOCAL)地址不同,因此相等的类型似乎不等于dynamic_cast()

有没有办法执行以下操作之一:

  • 仅加载type_info个对象,就像提供了RTLD_GLOBAL一样。
  • 使编译器使用类名比较而不是type_info地址来比较类型。

?我们使用的编译器是:

$ icpc -V
Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 12.0.0.084 Build 20101006
Copyright (C) 1985-2010 Intel Corporation.  All rights reserved.

2 个答案:

答案 0 :(得分:4)

好的,我们最终做的是解决这个问题。

我们在类中添加了dynamic_cast()两个静态函数:

static MyClass* doNew();
static MyClass* doDynCast(MyBase*);

这些是在cpp文件中实现的,它将newdynamic_cast()type_info对象保存在同一个lib中,从而使dynamic_cast()能够解决问题

这个解决方案足以满足我们的特定情况,但是如果有人有更通用的解决方案,那将会受到欢迎。

我们发现的另一个选项是将类的所有实现放在cpp文件中,这使得typeinfo符号仅存在于一个库中,而所有其他库仅引用它。这导致成功dynamic_cast()

答案 1 :(得分:2)

不幸的是,因为type_info结构是创建它们的库本地的弱符号,所以不容易使dynamic_cast工作。您可以尝试操作类vtable(和type_info)实例化的位置;在GCC上,可以通过确保仅在公共共享依赖库中定义the first non-inline function in the class (in order of definition)来完成此操作。如果您的类没有非内联函数,请创建一个虚拟函数以强制执行此生成。但请注意,我没有对此进行测试,因此无法保证它能够正常工作。另外,这是依赖于编译器的;我不知道英特尔的编译器做了什么。

当然,您可以使用类名来实现自己的备用动态转换机制;有许多库也可以这样做,例如Qt的qobject_cast