2008-12-25 16 views
8

当加载共享库通过函数dlopen()打开时,有没有办法让它在主程序中调用函数?加载的库函数如何在主应用程序中调用符号?

+0

下面的答案在回答这个问题方面做得很好,但我必须问 - 你能否解释这个要求的更广泛的背景?当我发现需要这样做时,要么是构建一个可扩展性/插件模型,要么是因为我的程序不是很好的考虑因素。 – reuben 2008-12-25 06:18:56

+0

它也可以用于倒置控制,不是吗?定义应用程序在库中的流程,而实际的实现在主应用程序中 – hhafez 2008-12-25 11:19:16

+0

想象一下Perl XS模块。它需要使用低级别的Perl函数(比如说newSViv()从一个整数中创建一个SV);如果模块使用Perl的newSViv()函数,而不是将其自己的副本嵌入到模块的共享对象中,则很方便。此外,代码需要标准的C库。 – 2008-12-25 19:35:29

回答

17

代码(的lib):与

gcc -shared -olibdlo.so dlo.c 

#include <stdio.h> 

// function is defined in main program 
void callb(void); 

void test(void) { 
    printf("here, in lib\n"); 
    callb(); 
} 

编译

这里的主程序代码(从dlopen手册页复制并调整):

#include <stdio.h> 
#include <stdlib.h> 
#include <dlfcn.h> 

void callb(void) { 
    printf("here, i'm back\n"); 
} 

int 
main(int argc, char **argv) 
{ 
    void *handle; 
    void (*test)(void); 
    char *error; 

    handle = dlopen("libdlo.so", RTLD_LAZY); 
    if (!handle) { 
     fprintf(stderr, "%s\n", dlerror()); 
     exit(EXIT_FAILURE); 
    } 

    dlerror(); /* Clear any existing error */ 

    *(void **) (&test) = dlsym(handle, "test"); 

    if ((error = dlerror()) != NULL) { 
     fprintf(stderr, "%s\n", error); 
     exit(EXIT_FAILURE); 
    } 

    (*test)(); 
    dlclose(handle); 
    exit(EXIT_SUCCESS); 
} 

使用Build

gcc -ldl -rdynamic main.c 

输出:

[[email protected] dlopen]$ LD_LIBRARY_PATH=. ./a.out 
here, in lib 
here, i'm back 
[[email protected] dlopen]$ 

-rdynamic选项把在动态符号表中的所有码元(其被映射到存储器中),不仅使用的符号的名称。详细了解它here。当然,你也可以提供函数指针(或者函数指针的结构)来定义库和主程序之间的接口。这实际上是我可能选择的方法。我从其他人那里听说,在Windows中做-rdynamic并不是那么容易,它也会使库和主程序之间的通信变得更清晰(你可以精确地控制可以调用的内容而不是),但它也需要更多的管家。

4

是的,如果您为库提供了一个指向该函数的指针,我相信该库将能够在主程序中运行/执行该函数。

下面是一个例子,并没有编译它所以要小心)dlo.c的

/* in main app */ 

/* define your function */ 

int do_it(char arg1, char arg2); 

int do_it(char arg1, char arg2){ 
    /* do it! */ 
    return 1; 
} 

/* some where else in main app (init maybe?) provide the pointer */ 
LIB_set_do_it(&do_it); 
/** END MAIN CODE ***/ 

/* in LIBRARY */ 

int (*LIB_do_it_ptr)(char, char) = NULL; 

void LIB_set_do_it(int (*do_it_ptr)(char, char)){ 
    LIB_do_it_ptr = do_it_ptr; 
} 

int LIB_do_it(){ 
    char arg1, arg2; 

    /* do something to the args 
    ... 
    ... */ 

    return LIB_do_it_ptr(arg1, arg2); 
} 
+0

do_it_ptr需要一个指向需要3个字符参数的函数的指针;你为只有2个字符参数的函数分配函数指针。 doit()的extern声明几乎不需要。 do_it_ptr不是必需的;你可以在你当前传递do_it_ptr的地方通过名字传递do_it。等等! – 2008-12-25 06:18:52

1

如@litb所述,dlopen()函数主要在使用ELF格式对象文件的系统上提供。它相当强大,并且可以让您控制是否可以从主程序中满足加载库引用的符号,并且通常会让它们满意。并非所有的共享库加载系统都是灵活的 - 请注意是否需要移植代码。

@hhafez概述的回调机制现在可以工作,该代码中的扭结被理顺了。

相关问题