Использование dlopen / dlsym для открытия разделяемой библиотеки C ++ - dlsym возвращает NULL - PullRequest
0 голосов
/ 17 мая 2018

Я еще не имел дело с общими библиотеками в 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

Здесь есть большая картина ( Создание модуля C ++ Redis - "не экспортирует RedisModule_OnLoad ()символ "), но я просмотрел исходный код 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

1 Ответ

0 голосов
/ 17 мая 2018

C ++ имеет перегрузку функций, поэтому может быть несколько функций с одним и тем же именем и только разными параметрами.

Поскольку объектные файлы хранят только имена, C ++ применяет так называемое искажение имен.Он добавляет дополнительные символы, представляющие параметры электронной почты, имя, чтобы различать разные версии.

При использовании dlsym, необходимо использовать искаженное имя, чтобы получить адрес функции.

Теперь, так как искажение имени является платформойВ частности, часто лучше использовать связь C (без искажения имени)

Это можно сделать с помощью объявления extern "C".

...