Вопрос по linux, dynamic-loading, shared-libraries, c++ – Получение неопределенной символьной ошибки при динамической загрузке разделяемой библиотеки

4

я осознаю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

Любая помощь будет оценена.

Когда-либо слышал терминискажение имени"? Это то, что, вероятно, происходит здесь, у вас есть код на C ++, но вы ищете неупорядоченное имя. Если вы хотите, чтобы это работало, объявите функцию фабрики какextern "C" { create_object(...) ... } в вашем коде. Помимо этого, вам нужно вызвать его какcreate() потому что иначе вы не выполняете вызов функции. FrankH.
Чтобы уточнить: вам нужноextern "C" { ... } бит в исходном коде дляlibshared.so чтобы получить правильные названия символов. Кроме того, если вы хотите проверить, верна ли моя гипотеза, просто запустите «nm libshared.so» и посмотрите, чтофактический имена есть. FrankH.
И так пометьте это как C ++, а не C Eregrith

Ваш Ответ

1   ответ
9

Имя Мэнлинг в действии здесь.

Если вы хотите использоватьdlopen() / dlsym() с общими библиотеками C ++ вам необходимо:

объявите функции, которые вы хотите просмотретьdlsym() какextern "C" { ... } так что компилятор C ++ создаетunmangled имена для них.
Это возможно только в том случае, если функция, к которой вы пытаетесь получить доступ, является функцией, не являющейся или не являющейся статической, и не перегруженной (только одна подпись); C ++ не может создавать неупорядоченные имена в других ситуациях.
Если кто-то попросил компилятор сделать это черезextern "C" { ... } и возможно создать незафиксированное имя, оно дословно заканчивается в таблице символов ELF. Вы можете посмотреть его, используяdlsym() Точно так же, как вы бы для любой функции C.Узнайте, чтоискромсанный имя функции, и используйте это в своем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 в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

Это означает, что для этой библиотеки, если вы хотите получить указатель на функциюstd::unexpected() от него, вам придется запроситьdlsym(hdl, "_ZN10__cxxabiv112__unexpectedEPFvvE"); чтобы поиск был успешным.

объяснение в принципе верное, но пример слегка отклонился:std::unexpected() является синонимом_ZSt10unexpectedv, но_ZN10__cxxabiv112__unexpectedEPFvvE соответствует__cxxabiv1::__unexpected(void (*)()). Alex Cohn
Я исправлюсь - вы правы в этом, конечно :) FrankH.

Похожие вопросы