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