Подтвердить что ты не робот

Альтернативы dlsym() и dlopen() в С++

У меня есть приложение, часть которого использует разделяемые библиотеки. Эти библиотеки связаны во время компиляции.
В Runtime загрузчик ожидает, что общий объект будет находиться в LD_LIBRARY_PATH, если не обнаружено, что все приложение завершилось с ошибкой "не удалось загрузить общие библиотеки". Обратите внимание, что нет гарантии, что клиент будет иметь библиотеку, в этом случае Я хочу, чтобы приложение оставило подходящее сообщение об ошибке, и независимая часть должна работать правильно.

Для этой цели я использую dlsym() и dlopen() для использования API в общей библиотеке. Проблема в том, что если у меня много функций в API, я должен получить к ним доступ индивидуально, используя dlsym() и ptrs, которые в моем случае приводят к повреждению памяти и сбоям кода.

Есть ли альтернативы для этого?

4b9b3361

Ответ 1

Общее решение вашей проблемы - объявить таблицу указателей на функции, сделать один dlsym(), чтобы найти его, а затем вызвать все остальные функции с помощью указателя на эту таблицу. Пример (непроверенный):

// libfoo.h
struct APIs {
   void  (*api1)(void);
   void *(*api2)(int);
   long  (*api3)(int, void *);
};

// libfoo.cc
void fn1(void) { ... }
void *fn2(int) { ... }
long fn3(int, void *) { ... }

APIs api_table = { fn1, fn2, fn3 };


// client.cc
#include "libfoo.h"
...
  void *foo_handle = dlopen("libfoo.so", RTLD_LAZY);
  if (!foo_handle) {
     return false;            // library not present
  }
  APIs *table = dlsym(foo_handle, "api_table");
  table->api1();              // calls fn1
  void *p = table->api2(42);  // calls fn2
  long x = table->api3(1, p); // calls fn3

P.S. Доступ к вашим функциям API индивидуально с помощью dlsym и указателей сам по себе не приводит к повреждению памяти и сбоям. Скорее всего, у вас просто есть ошибки.

EDIT:
Вы можете использовать эту ту же технику с сторонней библиотекой. Создайте libdrmaa_wrapper.so и поместите в него api_table. Свяжите обертку напрямую с libdrmaa.so.

В главном исполняемом файле dlopen("libdrmaa_wrapper.so", RTLD_NOW). Этот dlopen будет успешным, если (и только если) libdrmaa.so присутствует во время выполнения и предоставляет все функции API, которые вы использовали в api_table. Если это произойдет, один вызов dlsym предоставит вам доступ ко всему API.

Ответ 2

Вы можете перенести свое приложение на другое, которое сначала проверяет все необходимые библиотеки, и если что-то не хватает, ошибки выглядят красиво, но если все в порядке, оно запускает реальное приложение.

Ответ 3

Используйте ниже тип кода

Class DynLib
{
    /* All your functions */
    void fun1() {};
    void fun2() {};
    .
    .
    .
}

DynLib* getDynLibPointer()
{
    DynLib* x = new Dynlib;
    return x;
}

используйте dlopen() для загрузки этой библиотеки во время выполнения. и используйте dlsym() и вызовите getDynLibPointer(), который возвращает объект DynLib. от этого объекта вы можете получить доступ ко всем вашим функциям jst как obj.fun1().....

Это источник исходного кода метода С++, предложенного ранее.

Ответ 4

Ваша проблема в том, что разрешение неразрешенных символов выполняется очень рано - на Linux. Я считаю, что символы данных разрешаются при запуске процесса, а функциональные символы выполняются лениво. Поэтому в зависимости от того, какие символы вы не решили, и о какой статической инициализации вы продолжаете, вы не сможете получить доступ к вашему коду.

Мое предложение состояло в том, чтобы иметь приложение-оболочку, которое ловушки строки кода возврата/ошибки "не может загружать разделяемые библиотеки", а затем преобразует это во что-то более значимое. Если это является общим, его не нужно обновлять каждый раз, когда вы добавляете новую разделяемую библиотеку.

В качестве альтернативы вы можете запустить свою оболочку script ldd, а затем проанализировать вывод, ldd сообщит обо всех библиотеках, которые не найдены для вашего конкретного приложения.