Как "плагины", загружаемые libdl, могут ссылаться на символы в программе, которая их загрузила?
Представьте, что у вас есть приложение с архитектурой на основе плагинов, где каждый плагин является *.so
файл, который динамически загружается dlopen()
,
Основное приложение может ссылаться на символы через dlsym()
и поэтому он может вызывать функции плагина. Как плагин может вызывать функции основного приложения?
Я знаю, что основное приложение может предоставить структуру, полную указателей на функции, которые плагин может использовать для вызова приложения. Есть ли более простой способ, чем это?
Изменить: вот минимальный рабочий пример, чтобы показать, что я имею в виду:
app.h
:
#ifndef APP_H
#define APP_H
void app_utility(void);
#endif
app.c
:
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include "app.h"
void app_utility(void)
{
printf("app_utility()\n");
}
int main(int argc, char **argv)
{
void *handle;
void (*plugin_function)(void);
if (argc < 2) {
fprintf(stderr, "usage: ./app plugin.so\n");
exit(1);
}
handle = dlopen(argv[1], RTLD_NOW | RTLD_LOCAL);
if (!handle) {
fprintf(stderr, "error loading plugin: %s\n", dlerror());
exit(1);
}
plugin_function = dlsym(handle, "doit");
if (!plugin_function) {
fprintf(stderr, "error loading symbol: %s\n", dlerror());
dlclose(handle);
exit(1);
}
plugin_function();
dlclose(handle);
return 0;
}
plugin.c
:
#include <stdio.h>
#include "app.h"
void doit(void)
{
printf("doit()\n");
app_utility();
printf("did it!\n");
}
Пример использования:
$ gcc -o app app.c -ldl
$ gcc -shared -o plugin.so
$ ./app ./plugin.so
error loading plugin: ./plugin.so: undefined symbol: app_utility
1 ответ
Существует опция, которую вы можете передать gcc при вызове, чтобы создать исполняемый файл для основного приложения: -rdynamic
$ gcc -rdynamic -o app app.c -ldl
Документация GCC для -rdynamic
:
Передайте флаг
-export-dynamic
на линкер ELF, на цели, которые его поддерживают. Это указывает компоновщику добавлять все символы, а не только используемые, в таблицу динамических символов. Эта опция необходима для некоторых примененийdlopen
или разрешить получение следов из программы.
ld
страница справочника для --export-dynamic
включает этот параграф:
Если вы используете
dlopen
"Чтобы загрузить динамический объект, который должен ссылаться на символы, определенные программой, а не какой-либо другой динамический объект, вам, вероятно, потребуется использовать эту опцию при связывании самой программы.