RTLD_LOCAL and dynamic_cast on Linux

RTLD_LOCAL and dynamic_cast on Linux

本文关键字:on Linux cast and LOCAL RTLD dynamic      更新时间:2023-10-16

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

插件的一个库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.

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

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

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

这些是在cpp文件中实现的,该文件将newdynamic_cast()type_info对象保存在同一个库中,从而使dynamic_cast()变通解决此问题。

对于我们的具体情况,这个解决方案已经足够了,但如果有人有更通用的解决方案,它将受到欢迎。

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

不幸的是,由于type_info结构是创建它们的库的本地弱符号,因此很难使dynamic_cast工作。但是,您可以尝试操作类 vtable(和 type_info)实例化的位置;在 GCC 上,这可以通过确保类中的第一个非内联函数(按定义顺序)仅在公共共享依赖项库中定义来完成。如果您的类没有非内联函数,请创建一个虚拟函数来强制生成此类。但是请注意,我还没有对此进行测试,因此不能保证它会起作用。此外,这依赖于编译器;我不知道英特尔的编译器是做什么的。

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