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, fügen Sie einfach beim Erstellen der ausführbaren Datei ein Flag -Wl,--export-dynamic
hinzu . 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 -Wl,--dynamic-list=exported.txt
. Dies erfordert einige 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
Jetzt mit der exportierten Liste (exported.txt
):
{
extern "C"
{
exported_callback;
};
};
Sichtbare Symbole erstellen und prüfen:
$ 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
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:
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.
Ihre mylib.c müsste etwa so aussehen:
void (*callback)() = NULL;
void register_function( void (*in_main_func)())
{
callback = in_main_func();
}
void function_needing_callback()
{
callback();
}
-
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 dem
-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.