Tienes dos opciones, entre las que puedes elegir:
Opción 1:exporte todos los símbolos de su ejecutable. Esta es una opción simple, solo cuando construya el ejecutable, agregue una bandera -Wl,--export-dynamic
. Esto haría que todas las funciones estuvieran disponibles para las llamadas de la biblioteca.
Opción 2:cree un archivo de símbolos de exportación con una lista de funciones y use -Wl,--dynamic-list=exported.txt
. Esto requiere algo de mantenimiento, pero más preciso.
Para demostrar:biblioteca ejecutable simple y cargada dinámicamente.
#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;
}
Código de biblioteca (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;
}
Entonces, primero crea la biblioteca (este paso no difiere):
gcc -shared -fPIC lib.c -o libprog.so
Ahora crea el ejecutable con todos los símbolos exportados:
gcc -Wl,--export-dynamic main.c -o prog.exe -ldl
Ejecutar ejemplo:
$ ./prog.exe
Hello from main!
Hello from library!
Hello from callback!
Símbolos exportados:
$ objdump -e prog.exe -T | grep callback
00000000004009f4 g DF .text 0000000000000015 Base exported_callback
0000000000400a09 g DF .text 0000000000000015 Base unexported_callback
Ahora con la lista exportada (exported.txt
):
{
extern "C"
{
exported_callback;
};
};
Cree y verifique los símbolos visibles:
$ 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
Necesitará crear una función de registro en su .so para que el ejecutable pueda dar un puntero de función a su .so para su uso posterior.
Así:
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);
la función de registro necesita almacenar el puntero de función en una variable en .so donde la otra función en .so puede encontrarlo.
Tu mylib.c necesitaría verse así:
void (*callback)() = NULL;
void register_function( void (*in_main_func)())
{
callback = in_main_func();
}
void function_needing_callback()
{
callback();
}
-
Coloque el prototipo de su función principal en un archivo .h e inclúyalo en su código de biblioteca principal y dinámico.
-
Con GCC, simplemente compile su programa principal con el
-rdynamic
bandera. -
Una vez cargada, su biblioteca podrá llamar a la función desde el programa principal.
Una pequeña explicación adicional es que una vez compilada, su biblioteca dinámica tendrá un símbolo indefinido para la función que está en el código principal. Una vez que su aplicación principal cargue la biblioteca, el símbolo será resuelto por la tabla de símbolos del programa principal. He usado el patrón anterior varias veces y funciona de maravilla.