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

Yuv*_*uvi 4 c++ linux shared-libraries dynamic-loading

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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

任何帮助,将不胜感激.

Fra*_*kH. 9

你很可能在这里看到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
Run Code Online (Sandbox Code Playgroud)

这些是受损的名称,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
Run Code Online (Sandbox Code Playgroud)

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

  • 原则上解释是正确的,但是示例稍微偏离:`std :: unexpected()`与`_ZSt10unexpectedv`同义,但`_ZN10__cxxabiv112__unexpectedEPFvvE`对应于`__cxxabiv1 :: __ unexpected(void(*)())`. (2认同)