2013-06-13 10 views
15

Mam wspólną bibliotekę, które zaimplementowałem i chcę .so wywołać funkcję w programie głównym, który ładuje biblioteki.W jaki sposób biblioteka współużytkowana (.so) może wywoływać funkcję zaimplementowaną w programie ładującym?

Powiedzmy mam main.c (plik wykonywalny), która zawiera:

void inmain_function(void*); 
dlopen("libmy.so"); 

W my.c (kod dla libmy.so) Chcę zadzwonić inmain_function:

inmain_function(NULL); 

W jaki sposób biblioteka współużytkowana wywołuje inmain_function, niezależnie od tego, czy jest zdefiniowana w programie głównym, inmain_function.

Uwaga: Chcę wywołać symbol w pliku main.c z pliku my.c nie odwrotnie, co jest typowym sposobem użycia.

Odpowiedz

15

Musisz utworzyć funkcję rejestru w .so, aby plik wykonywalny mógł podać wskaźnik funkcji do pliku .so, ponieważ jest później używany.

Jak to:

void in_main_func() { 
// this is the function that need to be called from a .so 
} 

void (*register_function)(void(*)()); 
void *handle = dlopen("libmylib.so"); 

register_function = dlsym(handle, "register_function"); 

register_function(in_main_func); 

register_function musi przechowywać wskaźnik funkcji w zmiennej w .so gdzie inna funkcja w .so można go znaleźć.

Twój mylib.c będzie potrzeba wyglądać tak:

void (*callback)() = NULL; 

void register_function(void (*in_main_func)()) 
{ 
    callback = in_main_func(); 
} 

void function_needing_callback() 
{ 
    callback(); 
} 
+2

Wolę zrobić 'if (callback) {callback(); return 0; } else {return -1; } ', aby wskazać błąd i uniknąć wywoływania' NULL' (co byłoby fatalne). – glglgl

+0

W prawo, usunięto linię pięści. – user746527

0

Poniższa może być używany do załadowania biblioteki dynamicznej w kodzie (w przypadku ktoś przyszedł tu po patrząc na to, jak to zrobić):

void* func_handle = dlopen ("my.so", RTLD_LAZY); /* open a handle to your library */ 

void (*ptr)() = dlsym (func_handle, "my_function"); /* get the address of the function you want to call */ 

ptr(); /* call it */ 

dlclose (func_handle); /* close the handle */ 

Nie zapomnij umieścić #include <dlfcn.h> i link z opcja –ldl.

Możesz również dodać logikę, która sprawdza, czy zwrócono NULL. W takim przypadku możesz zadzwonić pod numer dlerror i podać kilka znaczących komunikatów opisujących problem.

Inne plakaty dostarczyły jednak bardziej odpowiednie odpowiedzi na twój problem.

+0

Chcę zadzwonić z .so do funkcji w pliku załaduje .so – 0x90

+0

Tak, to wywoła funkcję w bibliotece '.so' z innego pliku (na przykład twój główny). Czy to właśnie miałeś na myśli, przepraszam? – Nobilis

+0

Chcę wywołać funkcję w głównym z .so. – 0x90

22

Masz dwie opcje, z których można wybierać:

Wariant 1: eksport wszystkich symboli z pliku wykonywalnego. To jest prosta opcja, gdy budujesz plik wykonywalny, dodaj flagę -Wl,--export-dynamic. W ten sposób wszystkie funkcje będą dostępne dla wywołań biblioteki.

Opcja 2: utwórz plik symboli eksportu z listą funkcji i użyj -Wl,--dynamic-list=exported.txt. Wymaga to pewnych czynności konserwacyjnych, ale dokładniejszych.

Aby zademonstrować: prosty plik wykonywalny i dynamicznie ładowaną bibliotekę.

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

void exported_callback() /*< Function we want to export */ 
{ 
    printf("Hello from callback!\n"); 
} 

viud unexported_callback() /*< Function we don't want to export */ 
{ 
    printf("Hello from unexported callback!\n"); 
} 

typedef void (*lib_func)(); 

int call_library() 
{ 
    void  *handle = NULL; 
    lib_func func = NULL; 
    handle = dlopen("./libprog.so", RTLD_NOW | RTLD_GLOBAL); 
    if (handle == NULL) 
    { 
     fprintf(stderr, "Unable to open lib: %s\n", dlerror()); 
     return -1; 
    } 
    func = dlsym(handle, "library_function"); 

    if (func == NULL) { 
     fprintf(stderr, "Unable to get symbol\n"); 
     return -1; 
    } 

    func(); 
    return 0; 
} 

int main(int argc, const char *argv[]) 
{ 
    printf("Hello from main!\n"); 
    call_library(); 
    return 0; 
} 

Kod biblioteki (lib.c):

#include <stdio.h> 
int exported_callback(); 

int library_function() 
{ 
    printf("Hello from library!\n"); 
    exported_callback(); 
    /* unexported_callback(); */ /*< This one will not be exported in the second case */ 
    return 0; 
} 

Więc najpierw zbudować bibliotekę (krok ten nie różni):

gcc -shared -fPIC lib.c -o libprog.so 

Teraz zbudować wykonywalny z wszystkie symbole eksportowane:

gcc -Wl,--export-dynamic main.c -o prog.exe -ldl 

Run przykład:

$ ./prog.exe 
Hello from main! 
Hello from library! 
Hello from callback! 

Symbole expo rted:

$ objdump -e prog.exe -T | grep callback 
00000000004009f4 g DF .text 0000000000000015 Base  exported_callback 
0000000000400a09 g DF .text 0000000000000015 Base  unexported_callback 

Teraz z eksportowanego listy (exported.txt):

{ 
    extern "C" 
    { 
     exported_callback; 
    }; 
}; 

budowy & check widocznych symboli:

$ gcc -Wl,--dynamic-list=./exported.txt main.c -o prog.exe -ldl 
$ objdump -e prog.exe -T | grep callback 
0000000000400774 g DF .text 0000000000000015 Base  exported_callback 
+0

podczas kompilacji libprog.so w ten sposób odkryje, że exported_callback jest brakującym symbolem. – kritzikratzi

+1

ps. aby odpowiedzieć na moje własne pytanie: można wyłączyć błąd "niezdefiniowany symbol" i zadziała, np. w klangu z '-undefined dynamic_lookup'. na Linuksie z gcc działa to magicznie jak opisano w poście, ale nie mam pojęcia dlaczego. – kritzikratzi

4
  1. Put prototyp funkcji main jest w .h plik i dołącz go do kodu biblioteki głównej i dynamicznej.

  2. Z GCC po prostu skompiluj swój główny program flagą -rdynamic.

  3. Po załadowaniu biblioteka będzie mogła wywołać funkcję z głównego programu.

Nieco dalsze wyjaśnienie jest takie, że po kompilacji biblioteka dynamiczna będzie miała niezdefiniowany symbol dla funkcji, która jest w kodzie głównym. Po załadowaniu głównej aplikacji do biblioteki symbol zostanie rozwiązany przez tabelę symboli programu głównego. Użyłem powyższego wzoru wiele razy i działa jak urok.

+1

Po prostu ciekawy, co się stanie, jeśli kolejna wspólna biblioteka ma również symbol? – user746527

+0

Symbol głównej aplikacji zastąpi/zastąpi bibliotekę, chyba że funkcja biblioteki została zdefiniowana za pomocą słowa kluczowego 'static'. – mshildt

Powiązane problemy