Wie kann eine Shared Library (.so) eine Funktion aufrufen, die in ihrem Loader-Code implementiert ist?
Lesezeit: 5 Minuten
0x90
Ich habe eine gemeinsam genutzte Bibliothek, die ich implementiert habe, und möchte, dass die .so eine Funktion aufruft, die im Hauptprogramm implementiert ist, das die Bibliothek lädt.
Nehmen wir an, ich habe main.c (ausführbare Datei), die Folgendes enthält:
void inmain_function(void*);
dlopen("libmy.so");
In der my.c (dem Code für die libmy.so) möchte ich aufrufen inmain_function:
inmain_function(NULL);
Wie kann die gemeinsam genutzte Bibliothek aufrufen inmain_function ungeachtet der Tatsache inmain_function wird im Hauptprogramm definiert.
Hinweis: Ich möchte ein Symbol in main.c von my.c aufrufen, nicht umgekehrt, was die übliche Verwendung ist.
Waleri Atamaniouk
Sie haben zwei Möglichkeiten, aus denen Sie wählen können:
Option 1: Exportieren Sie alle Symbole aus Ihrer ausführbaren Datei. Dies ist eine einfache Option, nur wenn Sie eine ausführbare Datei erstellen, fügen Sie ein Flag hinzu -Wl,--export-dynamic. Dies würde alle Funktionen für Bibliotheksaufrufe verfügbar machen.
Option 2: Erstellen Sie eine Exportsymboldatei mit einer Liste von Funktionen und verwenden Sie sie -Wl,--dynamic-list=exported.txt. Dies erfordert etwas Wartung, ist aber genauer.
Zur Demonstration: einfache ausführbare und dynamisch geladene Bibliothek.
#include <stdio.h>
#include <dlfcn.h>
void exported_callback() /*< Function we want to export */
{
printf("Hello from callback!\n");
}
void 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;
}
Bibliothekscode (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;
}
Erstellen Sie also zuerst die Bibliothek (dieser Schritt unterscheidet sich nicht):
gcc -shared -fPIC lib.c -o libprog.so
Erstellen Sie nun eine ausführbare Datei mit allen exportierten Symbolen:
gcc -Wl,--export-dynamic main.c -o prog.exe -ldl
Beispiel ausführen:
$ ./prog.exe
Hello from main!
Hello from library!
Hello from callback!
Exportierte Symbole:
$ objdump -e prog.exe -T | grep callback
00000000004009f4 g DF .text 0000000000000015 Base exported_callback
0000000000400a09 g DF .text 0000000000000015 Base unexported_callback
Wenn Sie libprog.so so kompilieren, wird es feststellen, dass exported_callback ein fehlendes Symbol ist.
– Kritzikratzi
7. Dezember 2015 um 3:54 Uhr
p.s. um meine eigene frage zu beantworten: man kann den fehler “undefiniertes symbol” deaktivieren und es funktioniert, zB in clang with -undefined dynamic_lookup. Unter Linux mit gcc funktioniert dies auf magische Weise wie im Beitrag beschrieben, aber ich habe keine Ahnung warum.
– Kritzikratzi
8. Dezember 2015 um 6:06 Uhr
Dies ist eine so viel bessere Antwort als die akzeptierte! Ich wünschte, es wäre oben.
– SergejA
28. Februar 2019 um 19:50 Uhr
Benutzer746527
Sie müssen eine Registerfunktion in Ihrer .so-Datei erstellen, damit die ausführbare Datei Ihrer .so-Datei einen Funktionszeiger für die spätere Verwendung geben kann.
So was:
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);
die register_function muss den Funktionszeiger in einer Variablen in der .so-Datei speichern, wo ihn die andere Funktion in der .so-Datei finden kann.
Ich würde lieber tun if (callback) { callback(); return 0; } else { return -1; } um einen Fehler anzuzeigen und einen Anruf zu vermeiden NULL (was fatal wäre).
– glglgl
13. Juni 2013 um 8:18 Uhr
Richtig, die Faustlinie entfernt.
– Benutzer746527
14. Juni 2013 um 10:25 Uhr
Platzieren Sie den Prototyp Ihrer Hauptfunktion in einer .h-Datei und fügen Sie ihn sowohl in Ihren Haupt- als auch in Ihren dynamischen Bibliothekscode ein.
Mit GCC kompilieren Sie Ihr Hauptprogramm einfach mit der -rdynamic Flagge.
Nach dem Laden kann Ihre Bibliothek die Funktion vom Hauptprogramm aus aufrufen.
Eine kleine weitere Erklärung ist, dass Ihre dynamische Bibliothek nach dem Kompilieren ein undefiniertes Symbol für die Funktion enthält, die sich im Hauptcode befindet. Nachdem Ihre Haupt-App die Bibliothek geladen hat, wird das Symbol von der Symboltabelle des Hauptprogramms aufgelöst. Ich habe das obige Muster unzählige Male verwendet und es funktioniert wie ein Zauber.
Nur neugierig, was passiert, wenn eine andere gemeinsam genutzte Bibliothek das Symbol ebenfalls hat?
– Benutzer746527
14. Juni 2013 um 10:27 Uhr
Das Symbol der Hauptanwendung ersetzt/überschreibt das der Bibliothek, es sei denn, die Funktion der Bibliothek wurde mit definiert static Stichwort.
– mshildt
14. Juni 2013 um 12:51 Uhr
Nobilis
Folgendes kann verwendet werden, um eine dynamische Bibliothek zu laden und sie aus dem Ladeaufruf aufzurufen (falls jemand hierher kam, nachdem er nach dem Laden und Aufrufen einer Funktion in einer .so-Bibliothek gesucht hatte):
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 */
Vergessen Sie nicht zu setzen #include <dlfcn.h> und verlinke mit der –ldl Möglichkeit.
Möglicherweise möchten Sie auch eine Logik hinzufügen, die überprüft, ob NULL ist zurück gekommen. Wenn das der Fall ist, können Sie anrufen dlerror und es sollte Ihnen einige aussagekräftige Meldungen geben, die das Problem beschreiben.
Andere Poster haben jedoch passendere Antworten auf Ihr Problem gegeben.
13657800cookie-checkWie kann eine Shared Library (.so) eine Funktion aufrufen, die in ihrem Loader-Code implementiert ist?yes