posix shared-libraries d dlopen

posix - Funciones ejecutadas automáticamente al cargar bibliotecas compartidas



shared-libraries dlopen (4)

Al cargar bibliotecas compartidas en Windows, la llamada a LoadLibrary() hace que DllMain en la biblioteca se ejecute para cada nuevo proceso y la biblioteca de subprocesos se adjunta a, y para cada proceso y desde donde se separa la biblioteca de subprocesos.

¿Existe un mecanismo similar para Mac OS X, Linux y posiblemente otros sistemas operativos compatibles con POSIX?



Para C ++ puedes crear una clase y usar su constructor y destructor para inicializar la biblioteca.

Después, solo necesitas definir una variable para esta clase.

Ejemplo de inicialización de openssl en la biblioteca:

class InitLibrary { public: InitLibrary() { CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL''s use SSL_library_init(); // Initialize OpenSSL''s SSL libraries SSL_load_error_strings(); // Load SSL error strings ERR_load_BIO_strings(); // Load BIO error strings OpenSSL_add_all_algorithms(); // Load all available encryption algorithms } ~InitLibrary() { ERR_remove_state(0); CRYPTO_cleanup_all_ex_data(); ENGINE_cleanup(); } };

y solo agregue esta línea en el archivo cpp: InitLibrary InitLib;


Para ejecutar una función siempre que la biblioteca compartida esté cargada o descargada, puede marcar una función de constructor y destructor usando la sintaxis de atributo específica de GCC:

__attribute__((constructor)) void init(void) { ... } __attribute__((destructor)) void fini(void) { ... }

Debido a que varias partes de un entorno C dependen de las cosas que se inicializan en el código .init estándar agregado por GCC detrás de las escenas, el uso directo de -Wl,-init,<function name> puede hacer que su programa falle.

Para obtener más información, consulte Libary HOWTO on Library constructor and destructor functions .


Puede definir una función en carga para una biblioteca de Linux utilizando el mecanismo .init . Esto es lo mismo que especificar el punto de entrada del tiempo de carga para un archivo binario (por ejemplo, usar algo que no sea principal como punto de entrada para un programa).

Al vincular usando ld directamente, usa:

-init <function name>

o si está utilizando cc / gcc para vincular, utiliza:

-Wl,-init,<function name>

Este es el nivel más simple.

Editar Para destructores / finalizadores, usa el mecanismo .fini . Esto funciona de la misma manera que la opción init, y usted usa:

-fini <function name>

al invocar ld . La disponibilidad está limitada a la opción de entrada en la plataforma Mac OSX.

También debería poder usar la __attribute__((constructor)) para gcc:

static void con() __attribute__((constructor)); void con() { printf("I''m a constructor/n"); }

Que es probablemente una forma más portátil en lugar de atornillar con las opciones del enlazador. Todos los constructores deben invocarse en el momento de la carga, pero no dependen del orden de su inicialización, lo que conduce a la locura y errores no reproducibles que cuestan tiempo y esfuerzo para la depuración.

Editar 2 El uso del __attribute__((constructor))/__attribute__((destructor)) es el mecanismo más preferible para el lenguaje de programación C / C ++.

Para el lenguaje de programación D , realmente debería usar el constructor / destructor de módulos estáticos:

static this() { printf("static this for mymodule/n"); } static ~this() { printf("static ~this for mymodule/n"); }

O el constructor de clase estático:

class Foo { static this() { printf("static this for Foo/n"); } }

Esto se insinúa fuertemente en la escritura de win32 DLLS y en la especificación de lenguaje relacionada con constructores / destructores estáticos .

Editar 3 Tendrá que enlazar en un .o que exporta rutinas de constructor / destructor, que permitirá el uso de los inicializadores estáticos. Como todo lo que debe hacer es llamar a Runtime.initialize (), esto realmente invoca todos los constructores / destructores estáticos en el código D

Stub d code para el inicializador (en un archivo llamado myshared.d ):

import core.runtime; extern (C) { void attach(); void detach(); } export void attach() { Runtime.initialize(); } export void detach() { Runtime.terminate(); }

Crea el .o para este stub:

dmd -m32 -c myshared.d

Verifique los nombres de las funciones de adjuntar / separar:

nm myshared.o

Muestra (entre otros resultados):

0000001c S _D8myshared6attachFZv 00000034 S _D8myshared6detachFZv

Ejemplo de código .c para invocar esto (llamado export.c en este caso), hacemos referencia a los nombres de las rutinas exportadas desde my shared.o archivo my shared.o :

extern void D8myshared6attachFZv(void); extern void D8myshared6detachFZv(void); void __attach(void) __attribute__((constructor)); void __detach(void) __attribute__((destructor)); void __attach(void) { D8myshared6attachFZv(); } void __detach(void) { D8myshared6detachFZv(); }

Tenga en cuenta que las referencias de extern void necesitan usar el nombre destrozado de la función exportada. Estos deben coincidir o el código no se vinculará.

compila el código C usando:

gcc -m32 -c export.c

vincula los archivos .co y .do usando:

cc -o libmyshared.dylib -m32 -shared myshared.o export.o -lphobos2

Suponiendo que la biblioteca de phobos2 está en su ruta de búsqueda de vinculador estándar. Las -m32 opciones de -m32 para el compilador y el enlazador se deben a que la versión del compilador D que -m32 localmente solo admitía 32 bits.

Esto produce un .dylib al que se puede vincular. Parece funcionar en función de las pruebas limitadas que realicé. Parece que el soporte para bibliotecas compartidas de objetos / dinámicos es muy limitado, por lo que hay muchas posibilidades de que haya otro obstáculo que superar.