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

时间:2012-03-23 09:49:17

标签: 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);
}

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

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

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

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:9)

你很可能会在这里看到名字管理

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

  1. 将您想要通过dlsym()查找的函数声明为extern "C" { ... },以便C ++编译器为它们创建 unmangled 名称。
    只有当您尝试访问的函数是非成员函数或静态成员函数且未重载(仅一个签名)时,才可以执行此操作;在其他情况下,C ++无法创建未编码的名称 如果有人请求编译器通过extern "C" { ... }这样做,并且可以创建一个未编码的名称,它将在ELF符号表中逐字结束。然后,您可以使用dlsym()查找它,就像使用任何C函数一样。
  2. 找出该功能的受损名称,并在dlsym()电话中使用该名称。
  3. 后者可以通过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
    

    这些是 mangled 名称,C ++编译器实际放入ELF对象的名称。如果您使用-C选项请求nm demangle 您的姓名,您将获得:

    $ 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");使查找成功。