Oracle® Solaris 11.2 链接程序和库指南

退出打印视图

更新时间: 2014 年 7 月
 
 

父目标文件

提供可扩展功能的程序通常使用在运行时使用 dlopen() 函数装入的共享目标文件。这些共享目标文件通常称为插件,它们提供了一种用于扩展核心系统的功能的灵活方法。装入插件的目标文件称为父目标文件

父目标文件装入插件并从插件内访问函数和数据。对于父目标文件,通过插件提供要使用的函数和数据很常见。以下父目标文件和插件源文件对此进行了说明。为了利用插件,此处父目标文件提供了名为 parent_callback() 的函数。插件为父目标文件提供了名为 plugin_func() 的函数以供调用。

$ 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()

构建任何共享目标文件时,为了确保目标文件指定了其所有依赖项,建议使用 –z defs 选项。但是,由于父目标文件中有未满足的符号,使用 –z defs 会阻止插件目标文件进行链接。

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

可以使用 mapfile 向链接编辑指定 parent_callback() 符号由父目标文件提供。

$ cat plugin.mapfile
$mapfile_version 2

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

构建插件的首选解决方案是使用 –z parent 选项向插件提供对父目标文件的直接访问。使用 –z parent 而非 mapfile 的另一好处是父目标文件的名称将记录在插件的动态节中,并由 file 实用程序显示。

$ cc -zdefs -zparent=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