【问题标题】:Using dlopen/dlsym to open C++ shared library - dlsym returns NULL使用 dlopen/dlsym 打开 C++ 共享库 - dlsym 返回 NULL
【发布时间】:2018-05-17 17:46:44
【问题描述】:

我还没有处理过 C++ 中的共享库,遇到了一些麻烦。我想创建一个共享库,然后在该库上使用 C 函数。所以这是我的共享库文件:

extern int nothing();
//sym.cpp
int nothing() {
    return 0;
}

下面是我的 dlopen/dlsym 脚本:

//symtest.c
#include <stdio.h>
#include <dlfcn.h>
int main(){
    void *handle;
    handle = dlopen("/path/to/lib/sym.so",RTLD_NOW);
    int (*onload)(void *, void **, int);
    onload = (int (*)(void *, void **, int))(unsigned long) dlsym(handle,"nothing");
    if(onload==NULL) {
        printf("NULL");
    }
    return 0;
}

编译运行如下:

$ g++ -shared -fPIC -o sym.so sym.cpp
$ gcc symtest.c -ldl -o symtest
$ ./symtest
NULL

为什么我会得到 NULL?我很确定这个符号正在被导出,至少通过观察以下命令的输出。

纳米:

$ nm -CD sym.so | grep " T "                        
0000000000000670 T nothing()
000000000000067c T _fini
0000000000000518 T _init

objdump:

$ objdump -T sym.so 

sym.so:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000000518 l    d  .init  0000000000000000              .init
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize
0000000000200970 g    D  .bss   0000000000000000  Base        _end
0000000000200968 g    D  .got.plt   0000000000000000  Base        _edata
0000000000200968 g    D  .bss   0000000000000000  Base        __bss_start
0000000000000518 g    DF .init  0000000000000000  Base        _init
000000000000067c g    DF .fini  0000000000000000  Base        _fini
0000000000000670 g    DF .text  000000000000000b  Base        _Z7nothingv

这里有一个更大的图景 (Creating C++ Redis Module - "does not export RedisModule_OnLoad() symbol"),但我查看了一些 Redis 源代码以生成一个简约的示例。有人知道我在这里做错了什么吗?

根据要求,nm 不带 -C 选项:

$ nm -D sym.so
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
0000000000000670 T _Z7nothingv
0000000000200968 B __bss_start
                 w __cxa_finalize
                 w __gmon_start__
0000000000200968 D _edata
0000000000200970 B _end
000000000000067c T _fini
0000000000000518 T _init

【问题讨论】:

  • 您是否制作了 int nothing() extern "C" ?为什么不验证handle
  • 您需要指定错误名称 _Z7nothingv -- 我认为?
  • 我的意思是 extern "C" 而不仅仅是 extern,你听说过 C++ 中的名字修饰吗?
  • 你必须提供 C 风格的链接才能使用 C 代码 - 通常它不仅是修改,而且是 ABI
  • 是的,你必须这样做

标签: c++ g++ dlopen dlsym


【解决方案1】:

C++ 具有函数重载,因此可以有多个函数具有相同的名称和不同的参数。

由于目标文件只存储名称,C++ 应用了所谓的名称修饰。它添加了代表电子邮件参数名称的额外符号以区分不同版本。

使用 dlsym 时,必须使用重命名的名称才能获取函数地址。

现在由于名称修饰是特定于平台的,因此通常最好使用 C 链接(无名称修饰)

这可以通过extern "C" 声明来完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 2012-06-01
    相关资源
    最近更新 更多