Skip to content
Advertisement

How can “plugins” loaded by libdl refer to symbols in the program which loaded them?

Imagine that you have an application with a plugin based architecture, where each plugin is a *.so file that is dynamically loaded with dlopen().

The main application can refer to symbols via dlsym(), and so it may call functions of the plugin. How can the plugin call functions of the main application?

I know that the main application could provide a struct full of function pointers, which the plugin could use to call into the application. Is there any easier way than that?

Edit: here’s a minimal working example to show what I mean:

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.son");
        exit(1);
    }

    handle = dlopen(argv[1], RTLD_NOW | RTLD_LOCAL);
    if (!handle) {
        fprintf(stderr, "error loading plugin: %sn", dlerror());
        exit(1);
    }

    plugin_function = dlsym(handle, "doit");
    if (!plugin_function) {
        fprintf(stderr, "error loading symbol: %sn", 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");
}

Example usage:

$ gcc -o app app.c -ldl
$ gcc -shared -o plugin.so
$ ./app ./plugin.so
error loading plugin: ./plugin.so: undefined symbol: app_utility

Advertisement

Answer

There is a option you can pass to when you invoke it to create the executable for the main application: -rdynamic

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

The GCC documentation for -rdynamic:

Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of dlopen or to allow obtaining backtraces from within a program.

The ld manual page for --export-dynamic includes this paragraph:

If you use “dlopen” to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably need to use this option when linking the program itself.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement