Go to main content

Oracle® Solaris 11.4 Linkers and Libraries Guide

Exit Print View

Updated: October 2019
 
 

Parent Objects

Programs that offer extensible functionality often make use of shared objects, loaded at runtime using the dlopen() function. These shared objects are often referred to as plugins, and provide a flexible means to extend the abilities of the core system. The object that loads the plugins is referred to as the parent.

A parent object loads the plugin and accesses functions and data from within the plugin. It is also common for the parent object to provide functions and data for use by the plugin. This is illustrated by the following parent and plugin source files. Here the parent supplies a function named parent_callback() for the benefit of the plugin. The plugin supplies a function named plugin_func() for the parent to call.

$ cat main.c
#include    <stdio.h>
#include    <dlfcn.h>
#include    <link.h>

void
parent_callback(void)
{
        (void) printf("plugin_func() has called parent_callback()\n");
}

int
main(int argc, char **argv)
{
        typedef void plugin_func_t(void);

        void            *hdl;
        plugin_func_t   *plugin_func;

        if (argc != 2) {
                (void) fprintf(stderr, "usage: main plugin\n");
                return (1);
        }

        if ((hdl = dlopen(argv[1], RTLD_LAZY)) == NULL) {
                (void) fprintf(stderr, "unable to load plugin: %s\n",
                    dlerror());
                return (1);
        }

        plugin_func = (plugin_func_t *) dlsym(hdl, "plugin_func");
        if (plugin_func == NULL) {
                (void) fprintf(stderr, "unable to find plugin_func: %s\n",
                    dlerror());
                return (1);
        }

        (*plugin_func)();

        return (0);
}

$ cat plugin.c
#include    <stdio.h>

extern void parent_callback(void);

void
plugin_func(void)
{
        (void) printf("parent has called plugin_func() from plugin.so\n");
        parent_callback();
}

$ cc -o main main.c -lc
$ cc -Kpic -G -o plugin.so plugin.c -lc
$ ./main ./plugin.so
parent has called plugin_func() from plugin.so
plugin_func() has called parent_callback()

When building any shared object, the –z defs option is recommended, in order to ensure that the object specifies all of its dependencies. However, the use of –z defs prevents the plugin object from linking due to the unsatisfied symbol from the parent object.

$ cc -z defs -Kpic -G -o plugin.so plugin.c -lc
Undefined                       first referenced
 symbol                             in file
parent_callback                     plugin.o
ld: fatal: symbol referencing errors

A mapfile can be used to specify to the link-edit that the parent_callback() symbol is supplied by the parent object.

$ cat plugin.mapfile
$mapfile_version 2

SYMBOL_SCOPE {
        global:
               parent_callback         { FLAGS = PARENT };
};
$ cc -z defs -Mplugin.mapfile -Kpic -G -o plugin.so plugin.c -lc

The preferred solution for building a plugin is to use the –z parent option to provide the plugin with direct access to symbols from the parent. An added benefit of using –z parent instead of a mapfile, is that the name of the parent object is recorded in the dynamic section of the plugin, and is displayed by the file utility.

$ cc -z defs -z parent=main -Kpic -G -o plugin.so plugin.c -lc
$ elfdump -d plugin.so | grep PARENT
     [0]  SUNW_PARENT       0xcc                main
$ file plugin.so
plugin.so: ELF 32-bit LSB dynamic lib 80386 Version 1, parent main, \
    dynamically linked, not stripped