2008-12-25 93 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概述的回調機制現在可以工作,該代碼中的扭結被理順了。

相關問題