从 dlopen 加载的函数可以调用加载它的可执行文件中的函数吗?

Mah*_*koe 4 c c++ dlopen

设置

假设我用 C/C++ 编写了一个程序并希望允许加载插件。典型的解决方案是将插件编写为:

插件.c

int my_plugin_fn() {
    return 7;
}
Run Code Online (Sandbox Code Playgroud)

并使用类似的东西编译它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;
}
Run Code Online (Sandbox Code Playgroud)

我用 编译了 loader.c gcc -o loader loader.c -ldl,运行后,输出为Plugin object returned: 7,正如预期的那样。

问题

假设我们想在主程序(loader.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;
}
Run Code Online (Sandbox Code Playgroud)

插件_v2.c

extern int times_2(int);

int my_plugin_fn() {
    return times_2(7);
}
Run Code Online (Sandbox Code Playgroud)

以与以前相同的方式编译和运行这些文件会生成Could not open shared object: ./loader_v2: symbol lookup error: ./plugin_v2.so: undefined symbol: times_2.

有没有办法使用加载插件dlopen()的程序中的调用函数来加载插件?

Emp*_*ian 5

有没有办法使用 dlopen() 调用函数从加载插件的程序加载插件?

是的,但是您想要从主可执行文件调用的函数必须从中导出,默认情况下不会发生这种情况。您可以使用 来查看从主二进制文件中导出了哪些符号nm -D loader

您可以通过将主可执行文件与标志链接来导出主可执行文件中定义的所有-rdynamic函数。

一些链接器,尤其是较新版本的 GNU-ld、GOLD 和 LLD,支持该--export-dynamic-symbol标志,允许有选择地仅导出您需要的符号。

在您的情况下,您可以将loader可执行文件链接到-Wl,--export-dynamic-symbol=times_2.