Как загруженная библиотечная функция будет вызывать символ в основном приложении? - PullRequest
9 голосов
/ 25 декабря 2008

Когда загруженная разделяемая библиотека открывается через функцию dlopen(), есть ли способ вызвать ее в основной программе?

Ответы [ 3 ]

20 голосов
/ 25 декабря 2008

Код dlo.c (библиотека):

#include <stdio.h>

// function is defined in main program
void callb(void);

void test(void) {
    printf("here, in lib\n");
    callb();
}

Компилировать с

gcc -shared -olibdlo.so dlo.c

Здесь код основной программы (скопирован с man-страницы dlopen и настроен):

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void callb(void) {
    printf("here, i'm back\n");
}

int
main(int argc, char **argv)
{
    void *handle;
    void (*test)(void);
    char *error;

    handle = dlopen("libdlo.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    dlerror();    /* Clear any existing error */

    *(void **) (&test) = dlsym(handle, "test");

    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }

    (*test)();
    dlclose(handle);
    exit(EXIT_SUCCESS);
}

Сборка с

gcc -ldl -rdynamic main.c

Выход:

[js@HOST2 dlopen]$ LD_LIBRARY_PATH=. ./a.out
here, in lib
here, i'm back
[js@HOST2 dlopen]$

Опция -rdynamic помещает все символы в таблицу динамических символов (которая отображается в памяти), а не только имена используемых символов. Подробнее об этом читайте здесь . Конечно, вы также можете предоставить указатели на функции (или структуру указателей на функции), которые определяют интерфейс между библиотекой и вашей основной программой. Это на самом деле метод, который я бы выбрал, вероятно. Я слышал от других людей, что это не так просто сделать -rdynamic в Windows, и это также улучшит связь между библиотекой и основной программой (у вас есть точный контроль над тем, что можно вызывать, а что нет), но это также требует больше домашнего хозяйства.

4 голосов
/ 25 декабря 2008

Да, если вы предоставите своей библиотеке указатель на эту функцию, я уверен, что библиотека сможет запускать / выполнять функцию в основной программе.

Вот пример, не скомпилируйте его, так что будьте осторожны;)

/* in main app */

/* define your function */

int do_it( char arg1, char arg2);

int do_it( char arg1, char arg2){
  /* do it! */
  return 1;
}

/* some where else in main app (init maybe?) provide the pointer */
 LIB_set_do_it(&do_it);
/** END MAIN CODE ***/

/* in LIBRARY */

int (*LIB_do_it_ptr)(char, char) = NULL;

void LIB_set_do_it( int (*do_it_ptr)(char, char) ){
    LIB_do_it_ptr = do_it_ptr;
}

int LIB_do_it(){
  char arg1, arg2;

  /* do something to the args 
  ...
  ... */

  return LIB_do_it_ptr( arg1, arg2);
}
1 голос
/ 25 декабря 2008

Функция dlopen(), о которой говорил @litb, в основном предоставляется в системах, использующих объектные файлы в формате ELF. Он достаточно мощный и позволит вам контролировать, могут ли символы, на которые ссылается загруженная библиотека, быть удовлетворенными из основной программы, и, как правило, позволяет им удовлетворяться. Не все системы загрузки разделяемых библиотек настолько гибки - имейте в виду, если речь идет о переносе кода.

Механизм обратного вызова, описанный @hhafez, теперь работает, когда изломы в этом коде выпрямлены.

...