2010-04-10 39 views
1

我有一个应用程序可以利用在运行时使用dlopen加载的插件。每个插件定义一个函数来检索使用通用结构定义的插件信息。类似的东西:dlopen/dlsym尽可能少链接

struct plugin { 
    char *name; 
    char *app_version; 
    int app_verion_id; 
    char *plugin_version; 
    int plugin_version_id; 
    /* ... */ 
}; 

struct plugin p = { "sample plugin",APP_VERION,APP_VERSION_ID,"1.2.3",10203 }; 

struct plugin *get_plugin() { 
    return &p; 
} 

这很好,插件可以加载。现在我想构建一个小工具来读取这些属性,而无需链接整个应用程序。为了做到这一点,我有这样的代码:

void *handle; 
struct plugin *plugin; 
struct plugin *(get_plugin*)(); 

handle = dlopen(filename, RTLD_LAZY); 
if (!handle) { /*...return; ...*/ } 

get_plugin = dlym(handle, "get_plugin"); 
if (!get_plugin) { /*...return; ...*/ } 

plugin = get_plugin(); 
printf("Plugin: %s\n", plugin->name); 

这对于简单的插件很好。问题在于许多插件引用了来自应用程序的更多符号,即使设置了RTLD_LAZY,也可以解析这些符号。 (如应用程序中用于初始化插件全局事物的全局变量)因此,dlopen()调用失败,并出现如fatal: relocation error: file sample_plugin.so: symbol application_some_symbol: referenced symbol not found这样的错误。因为我只想访问单个简单结构,所以我想知道如何阻止链接器完成他的大部分工作。

+0

构建插件时使用了哪些链接选项? – 2010-04-10 17:40:16

回答

1

如果您使用的是精灵二进制文件,您可能想查看您的平台是否有libelf可用。 尝试man elf了解更多信息。这可能会让你得到你所需要的,而不必实际链接。我从来没有用过它,所以我不知道。

+0

谢谢,基于Solaris的gelf(3ELF)手册页的一个例子,我创建了一个小工具,它在运行时生成一个.so,所有需要的符号,然后加载这个.so,然后dlopen()是我的插件。有点hackish,但工作:-) (可能我可能已经做了一个shell脚本配对ldd输出,也...现在可以工作,我可以在这里组织我的插件) – johannes 2010-04-16 15:28:40

+0

嗯,你可能比我更聪明已经制作了该工具。很有意思。很高兴我可以提供帮助。 – nategoose 2010-04-20 23:25:46

0

怎么样一个肮脏的黑客与objdump

~$ objdump -s -j .rodata plugin.so 

plugin.so:  file format elf32-i386 

Contents of section .rodata: 
20000000 73616d70 6c652070 6c756769 6e00332e sample plugin.3. 
20000010 322e3100 312e322e 3300    2.1.1.2.3.  

1

根据man dlopen(重点是我的)

RTLD_LAZY

执行延迟绑定。
仅当 引用它们的代码被执行时才解析符号。如果 符号从未被引用,那么它将永远不会被解析。 (懒惰绑定 仅供功能 引用执行;引用 加载 库时,总是会立即绑定变量。)

所以,你需要添加到您的工具所有的全局变量,你的插件可能会使用。

+0

是的,我希望有人会有一个变通的想法: -/ – johannes 2010-04-10 18:51:58