Может ли функция, загруженная из dlopen, вызвать функцию из исполняемого файла, который ее загрузил? - PullRequest
4 голосов
/ 05 августа 2020

Настройка

Предположим, я написал программу на C / C ++ и хотел разрешить загрузку плагина. Типичным решением было бы написать плагин как:

plugin. c

int my_plugin_fn() {
    return 7;
}

и скомпилировать его, используя что-то вроде gcc -fpic -shared -o plugin.so plugin.c

Затем в основной программе, загружающей этот плагин, мы могли бы иметь:

загрузчик. c

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

int main() {
    void *plugin_handle = dlopen("./plugin.so", RTLD_LAZY);
    if (!plugin_handle) {
        printf("Could not open shared object: %s\n", dlerror());
        return -1;
    }

    int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
    char *err = dlerror();
    if (err) {
        printf("Could not resolve symbol: %s\n", err);
        return -1;
    }

    printf("Plugin object returned: %d\n", fn());

    return 0;
}

Я скомпилировал загрузчик. c с gcc -o loader loader.c -ldl, и после его запуска результат был Plugin object returned: 7, как и ожидалось.

Вопрос

Предположим, мы хотим добавить функции в нашу основную программу (загрузчик. c) которые могут использовать плагины. Например,

loader_v2. c

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

int times_2(int x) {
    return 2*x;
}

int main() {
    void *plugin_handle = dlopen("./plugin_v2.so", RTLD_LAZY);
    if (!plugin_handle) {
        printf("Could not open shared object: %s\n", dlerror());
        return -1;
    }

    int (*fn)() = dlsym(plugin_handle, "my_plugin_fn");
    char *err = dlerror();
    if (err) {
        printf("Could not resolve symbol: %s\n", err);
        return -1;
    }

    printf("Plugin object returned: %d\n", fn());

    return 0;
}

plugin_v2. c

extern int times_2(int);

int my_plugin_fn() {
    return times_2(7);
}

Компиляция и запуск этих файлов таким же образом, как и раньше, дает Could not open shared object: ./loader_v2: symbol lookup error: ./plugin_v2.so: undefined symbol: times_2.

Есть ли способ загрузить плагины, используя dlopen() функции вызова из программы, которая их загрузила?

Ответы [ 2 ]

4 голосов
/ 18 августа 2020

Есть ли способ загрузить плагины с помощью функций вызова dlopen () из программы, которая их загрузила?

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

Вы можете экспортировать все функции, определенные в основном исполняемом файле, связав его с флагом -rdynamic.

Некоторые компоновщики, особенно новые версии GNU-ld, GOLD и LLD, поддерживают флаг --export-dynamic-symbol, который позволяет выборочно экспортировать только необходимые символы.

В вашем случае вы должны связать исполняемый файл loader с -Wl,--export-dynamic-symbol=times_2.

1 голос
/ 05 августа 2020

Лучший способ сделать что-то подобное - использовать указатель на функцию. Вы передадите указатель функции в библиотечную функцию, которая впоследствии вызовет ее. вот так:

int (*fn)(int (*)(int)) = dlsym(plugin_handle, "my_plugin_fn");

А библиотечную функцию можно было бы вызвать так:

printf("Plugin object returned: %d\n", fn(times_2));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...