3

想象一下,您有一个基于插件架构的应用程序,其中每个插件都是一个*.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
4

1 回答 1

1

当您调用它来为主应用程序创建可执行文件时,您可以将一个选项传递给-rdynamic

$ gcc -rdynamic -o app app.c -ldl

GCC-rdynamic文档:_

将标志传递-export-dynamic给支持它的目标上的 ELF 链接器。这指示链接器将所有符号(不仅是使用的符号)添加到动态符号表中。对于某些用途dlopen或允许从程序中获取回溯,需要此选项。

ld手册页包括--export-dynamic以下段落:

如果您使用 " dlopen" 加载需要引用程序定义的符号的动态对象,而不是其他一些动态对象,那么在链接程序本身时可能需要使用此选项。

于 2018-03-15T23:50:13.120 回答