Máte dvě možnosti, ze kterých si můžete vybrat:
Možnost 1:exportujte všechny symboly ze spustitelného souboru. Toto je jednoduchá možnost, stačí při sestavování spustitelného souboru přidat příznak -Wl,--export-dynamic
. Tím by byly všechny funkce dostupné pro volání knihovny.
Možnost 2:vytvořte soubor se symbolem exportu se seznamem funkcí a použijte -Wl,--dynamic-list=exported.txt
. To vyžaduje určitou údržbu, ale je přesnější.
Pro demonstraci:jednoduchá spustitelná a dynamicky načítaná knihovna.
#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;
}
Kód knihovny (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;
}
Nejprve tedy vytvořte knihovnu (tento krok se neliší):
gcc -shared -fPIC lib.c -o libprog.so
Nyní sestavení spustitelného souboru se všemi exportovanými symboly:
gcc -Wl,--export-dynamic main.c -o prog.exe -ldl
Spustit příklad:
$ ./prog.exe
Hello from main!
Hello from library!
Hello from callback!
Exportované symboly:
$ objdump -e prog.exe -T | grep callback
00000000004009f4 g DF .text 0000000000000015 Base exported_callback
0000000000400a09 g DF .text 0000000000000015 Base unexported_callback
Nyní s exportovaným seznamem (exported.txt
):
{
extern "C"
{
exported_callback;
};
};
Vytvořte a zkontrolujte viditelné symboly:
$ 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
Budete muset vytvořit funkci registru ve vašem .so, aby spustitelný soubor mohl poskytnout ukazatel funkce na váš .so pro jeho pozdější použití.
Takhle:
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);
funkce register musí uložit ukazatel funkce do proměnné v .so, kde jej může najít jiná funkce v .so.
Váš mylib.c by musel vypadat nějak takto:
void (*callback)() = NULL;
void register_function( void (*in_main_func)())
{
callback = in_main_func();
}
void function_needing_callback()
{
callback();
}
-
Vložte prototyp své hlavní funkce do souboru .h a zahrňte jej do kódu hlavní i dynamické knihovny.
-
S GCC jednoduše zkompilujte svůj hlavní program s
-rdynamic
vlajka. -
Po načtení bude vaše knihovna schopna volat funkci z hlavního programu.
Trochu další vysvětlení je, že po zkompilování bude mít vaše dynamická knihovna nedefinovaný symbol pro funkci, která je v hlavním kódu. Jakmile vaše hlavní aplikace načte knihovnu, bude symbol vyřešen tabulkou symbolů hlavního programu. Výše uvedený vzor jsem použil mnohokrát a funguje jako kouzlo.