动态加载共享库时出现未定义的符号错误

Getting undefined symbol error while dynamic loading of shared library

本文关键字:未定义 符号 错误 加载 共享 动态      更新时间:2023-10-16

动态加载库时出现undefined symbol错误。以下是我生成此错误的代码片段:

int main ()
{
    void *lib_handle = NULL;
    MyClass* (*create)();
    void (*destroy)(MyClass*);
    char *error;

    lib_handle = dlopen ("./libshared.so", RTLD_LAZY);
    if (lib_handle == NULL) 
    {
        fprintf(stderr, "%sn", dlerror());
        exit(1);
    } 
    create = (MyClass* (*)()) dlsym(lib_handle, "create_object");
    if ((error = dlerror()) != NULL)  
   {
      fprintf(stderr, "%sn", error);
      exit(1);
   }
    destroy = (void (*)(MyClass*)) dlsym(lib_handle, "destroy_object");
    MyClass *myClass = (MyClass*) create;
    destroy(myClass);   
    dlclose(lib_handle);
}

但当我简单地通过注释上面的代码并导出库路径来加载库时,一切都像魅力一样。

对于动态链接,我在命令提示符下使用以下命令。

g++ -Wl,--export-dynamic shared_user.cpp -ldl

如有任何帮助,我们将不胜感激。

您很可能会在此处看到Name Mangling的操作。

如果您想将dlopen()/dlsym()与C++共享库一起使用,您需要:

  1. 将要通过dlsym()查找的函数声明为extern "C" { ... },以便C++编译器为它们创建未映射的名称
    只有当您尝试访问的函数是非成员或静态成员函数,并且没有重载(只有单个签名)时,这才有可能;在其他情况下,C++无法创建未映射的名称
    如果有人通过extern "C" { ... }请求编译器这样做,并且可以创建一个未映射的名称,那么它最终会逐字记录在ELF符号表中。然后,您可以使用dlsym()查找它,就像查找任何C函数一样
  2. 找出函数的损坏名称,并在dlsym()调用中使用该名称

后者可以通过nm实用程序完成。例如:

$ nm libstdc++.a | grep -v '^ ' | grep unexpected
0000000000000000 T __cxa_call_unexpected
0000000000000000 T _ZN10__cxxabiv112__unexpectedEPFvvE
0000000000000000 T _ZSt10unexpectedv
0000000000000000 T _ZSt14set_unexpectedPFvvE
0000000000000000 D _ZN10__cxxabiv120__unexpected_handlerE

这些是损坏的名称,是C++编译器实际放入ELF对象中的名称。如果您使用-C选项请求nm为您解组名称,则会得到:

$ nm -C libstdc++.a | grep -v '^ ' | grep unexpected
0000000000000000 T __cxa_call_unexpected
0000000000000000 T __cxxabiv1::__unexpected(void (*)())
0000000000000000 T std::unexpected()
0000000000000000 T std::set_unexpected(void (*)())
0000000000000000 D __cxxabiv1::__unexpected_handler

这意味着,对于这个lib,如果您想从中获得指向std::unexpected()的函数指针,则必须请求dlsym(hdl, "_ZN10__cxxabiv112__unexpectedEPFvvE");才能使查找成功。