GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo puede una biblioteca compartida (.so) llamar a una función que está implementada en su programa de carga?

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();
}

  1. 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.

  2. Con GCC, simplemente compile su programa principal con el -rdynamic bandera.

  3. 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.


Linux
  1. Linux:¿cómo garantizar que una biblioteca compartida tendrá sus páginas de memoria compartidas por varios procesos?

  2. ¿Por qué es /dev/null un archivo? ¿Por qué no se implementa su función como un programa simple?

  3. ¿Cómo llamar a una función Bash en Bash Script dentro de Awk?

  4. Cómo crear y llamar funciones en Bash

  5. Cómo inicializar una biblioteca compartida en Linux

Enlace estático de función de biblioteca compartida en gcc

¿Cómo hacer el control de versiones de una biblioteca compartida en Linux?

¿Cómo puedo obtener lo que ha devuelto mi función principal?

¿Cómo se puede usar la función eval en makefile?

No se puede llamar a la función de biblioteca estándar de C en Linux de 64 bits desde el código ensamblador (yasm)

¿Cómo verificar si una biblioteca compartida está instalada?