c++ - 虚拟异常类导致动态链接器错误

标签 c++ rtti libstdc++ dlopen vtable

在小型复制器中,带有 vtable 的异常类的类型信息/vtable 的符号查找失败。为什么会出错?是否有可能使 RTTI 对加载了 dlopen 的 vtable 的类正常工作?间接加载的目的是runtime binding based on cpu .

库.h:

#include <exception>
class myexception : public std::exception {
    virtual void info();
};
void f();

lib.cc:

#include "lib.h"
void myexception::info() {};
void f() { throw myexception(); }

主.cc:

#include "lib.h"
int main() {
    try { f(); }
    catch(myexception) {}
}

stub .cc:

#include <dlfcn.h>
#include <stdlib.h>
__attribute__((constructor)) void init() {
    dlopen("libreal.so", RTLD_NOW | RTLD_GLOBAL);
}

build.sh:

g++ lib.cc -Wall -Wextra -shared -o libf.so -fPIC -g
g++ main.cc -Wall -Wextra libf.so -fPIE -g
mv libf.so libreal.so
g++ stub.cc -Wall -Wextra -shared -o libf.so -fPIC -ldl -g

使用 GCC 或 clang+libstdc++:

./a.out |& c++filt 
./a.out: symbol lookup error: ./a.out: undefined symbol: typeinfo for myexception

,以及使用 clang+libc(或使用 -fPIC 而不是 -fPIE 的 GCC):

./a.out |& c++filt 
./a.out: symbol lookup error: ./a.out: undefined symbol: vtable for myexception

编辑: 最初的问题表明二进制文件是使用 GCC 段错误编译的。只有在没有 fPIC/fpic/fPIE/fpie 的情况下编译二进制文件时才会出现这种情况。 (Clang 不需要标志,并且关于 clang 行为的问题没有更新)。为了简化问题,我将问题编辑为仅询问运行时链接器问题而不是段错误。

最佳答案

来自 dlopen 的手册页:

RTLD_LAZY

Perform lazy binding. Only resolve symbols as the code that references them is executed. If the symbol is never referenced, then it is never resolved. (Lazy binding is only performed for function references; references to variables are always immediately bound when the library is loaded.)

这很重要。 GNU ld 默认实现惰性绑定(bind)。这意味着您的后期绑定(bind)方法可能适用于函数,但不适用于数据。 (Vtables 和 RTTI 信息是数据)。如果您使用 -z now 链接可执行文件(类似于 dlopenRTLD_NOW 标志),该方法也将停止对函数起作用。

有两种基本方法可以解决这种情况。

  1. 不要在库外使用myexception 的运行时数据(vtable 和类型信息)。这意味着您可以直接使用 myexception 做什么非常受限。您可以将引用运行时数据的所有操作包装在从库导出的非虚函数中。
  2. myexception 的运行时数据移动到 stub 库中。对于大多数 C++ 编译器,这意味着在那里定义第一个(按声明顺序)非内联虚函数。您可以在类的顶部声明一个虚拟虚函数,并在 stub.cc 中实现它。其余的可能在 lib.cc 中实现。

关于c++ - 虚拟异常类导致动态链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48246196/

相关文章:

c++ - 如何旋转yuv420数据?

c++ - 为什么类类型的成员需要初始化?

C++ 对象生命周期分析

c++ - 加载共享库 : libstdc++. so.6 时出错:错误的 ELF 类:ELFCLASS64

c++ - 具有 const 成员的对象的优先级队列比较器

c++ - 如何从 QImage/QLabel 中删除裁剪后的矩形?

c++ - 在 C++ 中将元素插入 2D Vector 的顺序

delphi - 如何在类构造函数中访问 RTTI?

delphi - 如何获取TRTTIParamter的默认值

gcc - 在 CentOS 7 上找不到 GLIBCXX_3.4.21