6

动态加载库时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, "%s\n", dlerror());
        exit(1);

    } 

    create = (MyClass* (*)()) dlsym(lib_handle, "create_object");
    if ((error = dlerror()) != NULL)  
   {
      fprintf(stderr, "%s\n", 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

任何帮助,将不胜感激。

4

1 回答 1

12

您很可能会在这里看到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

这意味着对于这个库,如果你想从中获取函数指针std::unexpected(),你必须请求dlsym(hdl, "_ZN10__cxxabiv112__unexpectedEPFvvE");使查找成功。

于 2012-03-23T10:55:28.157 回答