Как "плагины", загружаемые 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"Чтобы загрузить динамический объект, который должен ссылаться на символы, определенные программой, а не какой-либо другой динамический объект, вам, вероятно, потребуется использовать эту опцию при связывании самой программы.

Другие вопросы по тегам