C / C++ ¿Cómo Funciona El Enlace Dinámico En Diferentes Plataformas?


¿Cómo funciona el enlace dinámico en general?

En Windows (LoadLibrary), necesita un .dll para llamar en tiempo de ejecución, pero en tiempo de enlace, debe proporcionar un correspondiente .archivo lib o el programa no enlazará... ¿Qué hace el .archivo lib contiene? Una descripción de la .métodos dll? ¿No es eso lo que contienen los encabezados?

Relacionado, en *nix, no necesita un archivo lib... ¿Cómo sabe el compilador que los métodos descritos en el encabezado estarán disponibles en tiempo de ejecución?

As un novato, cuando piensas en cualquiera de los dos esquemas, entonces el otro, ninguno de ellos tiene sentido...

Author: Charlie, 2014-04-04

9 answers

Para responder a sus preguntas una por una:

  • La vinculación dinámica aplaza parte del proceso de vinculación al tiempo de ejecución. Se puede utilizar de dos maneras: implícita y explícita. Implícitamente, el enlazador estático insertará información en el ejecutable que hará que la biblioteca para cargar y resolver el símbolos necesarios. Explícitamente, debe llamar a LoadLibrary o dlopen manualmente, y luego GetProcAddress/dlsym para cada símbolo que necesitas usar. La carga implícita se usa para cosas como el sistema biblioteca, donde la implementación dependerá de la versión del sistema, pero la interfaz está garantizada. Carga explícita se utiliza para cosas como plug-ins, donde el la biblioteca que se cargará se determinará en tiempo de ejecución.

  • El archivo .lib solo es necesario para la carga implícita. Se contiene la información que la biblioteca realmente proporciona símbolo, por lo que el enlazador no se quejará de que el símbolo es undefined, y le dice al enlazador en qué biblioteca los símbolos ser situado, por lo que puede insertar la información necesaria para causar esta biblioteca se cargará automáticamente. Todos los archivos de encabezado decirle al compilador es que los símbolos existirán, en algún lugar; el el enlazador necesita el .lib para saber dónde.

  • Bajo Unix, toda la información se extrae de la .so. Por qué Windows requiere dos archivos separados, en lugar de poner toda la información en un archivo, no lo sé; es en realidad duplicando la mayor parte de la información, ya que el la información necesaria en el .lib también se necesita en el .dll. (Tal vez problemas de licencia. Puede distribuir su programa con el .dll, pero nadie puede enlazar contra las bibliotecas a menos que tienen un .lib.)

Lo principal a retener es que si desea carga implícita, debe proporcionar al enlazador la información adecuada, ya sea con un archivo .lib o .so, para que pueda insertar que información en el ejecutable. Y que si quieres expresa cargando, no puede hacer referencia a ninguno de los símbolos de la biblioteca directamente; tienes que llamar GetProcAddress/dlsym para obtener su se dirige a sí mismo (y hacer un casting divertido para usarlos).

 21
Author: James Kanze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 11:26:34

El archivo .lib en Windows no es necesario para cargar una biblioteca dinámica, simplemente ofrece una forma conveniente de hacerlo.

En principio, puede utilizar LoadLibrary para cargar la dll y luego usar GetProcAddress para acceder a las funciones proporcionadas por esa dll. La compilación del programa adjunto no necesita acceder a la dll en ese caso, solo se necesita en tiempo de ejecución (es decir. cuando LoadLibrary realmente se ejecuta). MSDN tiene un ejemplo de código.

La desventaja aquí es que es necesario escribir manualmente el código para cargar las funciones de la dll. En caso de que haya compilado la dll usted mismo en primer lugar, este código simplemente duplica el conocimiento que el compilador podría haber extraído del código fuente de la dll automáticamente (como los nombres y firmas de las funciones exportadas).

Esto es lo que hace el archivo .lib: Contiene las llamadas GetProcAddress para las funciones Dlls exportadas, generadas por el compilador para que no tenga que preocuparse por ello. En términos de Windows, esto es llamado Enlace Dinámico en Tiempo de Carga, dado que el Dll se carga automáticamente por el código de la .archivo lib cuando se carga el programa adjunto (a diferencia del enfoque manual, conocido como enlace dinámico en tiempo de ejecución).

 13
Author: ComicSansMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 11:11:27

¿Cómo funciona el enlace dinámico en general?

El archivo dynamic link library (también conocido como shared object) contiene instrucciones y datos de código máquina, junto con una tabla de metadatos que dice qué compensaciones en ese código/datos se relacionan con qué "símbolos", el tipo del símbolo (por ejemplo, función vs datos), el número de bytes o palabras en los datos, y algunas otras cosas. Diferentes sistemas operativos tenderán a tener diferentes formatos de archivo de objeto compartido, y de hecho el mismo sistema operativo puede soportar varios, pero eso es lo esencial.

Entonces, imagine que la biblioteca compartida es un gran trozo de bytes con un índice como este:

SYMBOL       ADDRESS        TYPE        SIZE
my_function  1000           function    2893
my_number    4800           variable    4

En general, no es necesario capturar el tipo exacto de los símbolos en la tabla de metadatos; se espera que las declaraciones en los archivos de encabezado de la biblioteca contengan toda la información faltante. C++ es un poco especial, en comparación con C, porque la sobrecarga puede significar que hay varias funciones con el mismo nombre, y los espacios de nombres permiten más símbolos que de lo contrario se nombrará ambiguamente - por esa razón name mangling se usa típicamente para concatenar alguna representación del espacio de nombres y argumentos de función al nombre de la función, formando algo que puede ser único en el archivo objeto de la biblioteca.

Un programa que quiera usar el objeto compartido generalmente puede hacer una de dos cosas:

  • Haga que el sistema operativo cargue tanto él mismo como el objeto compartido aproximadamente al mismo tiempo (antes de ejecutar main()), con el cargador del sistema operativo responsable para encontrar los símbolos y examinar los metadatos en la imagen del archivo de programa sobre el uso de esos símbolos, luego parchear las direcciones de los símbolos en la memoria que usa el programa, de modo que el programa pueda ejecutarse y funcionar funcionalmente como si hubiera sabido sobre las direcciones de los símbolos cuando se compiló por primera vez (pero quizás un poco más lento)

  • O, explícitamente en su propio código fuente llame a dlopen en algún momento después de que se ejecute main, luego use dlsym o similar para obtener las direcciones de símbolo, guárdelas en punteros (función / datos) basados en el conocimiento del programador de los tipos de datos esperados, luego llámelos explícitamente usando los punteros.

En Windows (LoadLibrary), necesita un .dll para llamar en tiempo de ejecución, pero en tiempo de enlace, debe proporcionar un correspondiente .archivo lib o el programa no enlazará...

Eso no suena bien. Debería ser uno o el otro, creo.

Wtf hace el .archivo lib contiene? Una descripción de la .métodos dll? ¿No es eso lo que contienen los encabezados?

Un archivo lib es - en este nivel de descripción - casi lo mismo que un archivo objeto compartido... la principal diferencia es que el compilador encuentra las direcciones de los símbolos antes de que el programa sea enviado y ejecutado.

 8
Author: Tony Delroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 12:01:15

Modern *nix systems derive process of dynamic linking from Solaris OS. Linux, particularmente, no necesita separarse.archivo lib porque todas las dependencias externas están contenidas en formato ELF. .interp la sección del archivo ELF indica que hay símbolos externos dentro de este ejecutable que necesitan ser resueltos dinámicamente. Esto viene para dynamic linking.

Hay una manera de manejar el enlace dinámico en el espacio de usuario. Este método se llama carga dinámica. Aquí es cuando está utilizando llamadas al sistema para obtener punteros de función a métodos externos *.so.

Se puede encontrar más información en este artículo http://www.ibm.com/developerworks/library/l-dynamic-libraries/.

 2
Author: mesmerizingr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 11:12:01

Relacionado, en OS X (y supongo que *nix... dlopen), no necesita un archivo lib... ¿Cómo sabe el compilador que los métodos descritos en el encabezado estarán disponibles en tiempo de ejecución?

Los compiladores o enlazadores no necesitan tal información. Usted, el programador, necesita manejar la situación de que las bibliotecas compartidas que intenta abrir por dlopen() pueden no existir.

 2
Author: Lee Duhem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-05 08:34:43

Puede usar un archivo DLL en Windows de dos maneras: O lo vincula con él, y ya está, nada más que hacer. O lo carga dinámicamente durante el tiempo de ejecución.

Si se enlaza con él, se utiliza el archivo de biblioteca DLL. La biblioteca de enlaces contiene información que el enlazador utiliza para saber realmente qué DLL cargar y dónde están las funciones DLL, para que pueda llamarlas. Cuando se carga su programa, el sistema operativo también carga el DLL por usted, básicamente, ¿cómo se llama LoadLibrary para ti.

En otros sistemas operativos (como OS X y Linux) funciona de manera similar. La diferencia es que en estos sistemas el enlazador puede mirar directamente a la biblioteca dinámica (el .so/.dynlib archivo) y averiguar lo que se necesita sin una biblioteca estática separada como en Windows.

Para cargar una biblioteca dinámicamente, no necesita enlazar con nada relacionado con la biblioteca que desea cargar.

 2
Author: Some programmer dude,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-05 08:36:08

Como otros ya han dicho: lo que se incluye en un archivo .lib en Windows se incluye directamente en el .so/.dynlib en Linux / OS X . Pero la pregunta principal es... ¿Por qué? ¿No es mejor la solución *nix? Creo que lo es, pero el .lib tiene una ventaja. El desarrollador que se vincula a la DLL en realidad no necesita tener acceso al archivo DLL en sí.

¿Sucede a menudo un escenario como ese en el mundo real? ¿Vale la pena el esfuerzo de mantener dos archivos por archivo DLL? Yo no saber.

Editar: Ok, chicos vamos a hacer las cosas aún más confusas! Puedes enlazar directamente a una DLL en Windows, usando MinGW. Así que todo el problema de la biblioteca de importación no está directamente relacionado con Windows. Tomado de sampleDLL artículo de la wiki de MinGW:

La biblioteca de importación creada por la opción de enlazador "out out-implib" es iff requerido (==si y solo si) la DLL se interconectará desde algunos Compilador de C / C++ que no sea la cadena de herramientas MinGW. El MinGW la cadena de herramientas es perfectamente feliz de vincular directamente contra el DLL creado. Más detalles se puede encontrar en el ld.archivos de información exe que forman parte de los binutils paquete (que es una parte de la cadena de herramientas).

 2
Author: cubuspl42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-05 17:45:23

Linux también requiere enlazar, pero en su lugar contra a .Biblioteca Lib necesita enlazar al enlazador dinámico /lib/ld-linux.so.2, pero esto suele ocurrir entre bastidores cuando se usa GCC (sin embargo, si se usa un ensamblador, es necesario especificarlo manualmente).

Ambos enfoques, ya sea las Ventanas .El enfoque LIB o el enfoque linker linking dinámico de Linux, son considerados en realidad como enlaces estáticos. Hay, sin embargo, una diferencia que en Windows parte del trabajo se realiza en tiempo de enlace aunque todavía tiene trabajo en tiempo de carga (no estoy seguro, pero creo que el .LIB file es simplemente para que el enlazador conozca el nombre de la biblioteca física, sin embargo, los símbolos solo se resuelven en tiempo de carga), mientras que en Linux todo, además de la vinculación al enlazador dinámico, ocurre en tiempo de carga.

El enlace dinámico se refiere en general a abrir manualmente el archivo DLL en tiempo de ejecución (como usar LoadLinrary()), en cuyo caso la carga recae enteramente en el programador.

 1
Author: yoel halb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-05 08:40:08

En una biblioteca compartida, como .dll .dylib y .so, hay alguna información sobre el nombre y la dirección del símbolo, como esta:

------------------------------------
| symbol's name | symbol's address |
|----------------------------------|
| Foo           | 0x12341234       |
| Bar           | 0xabcdabcd       |
------------------------------------

Y la función load, como LoadLibrary y dlopen, carga la biblioteca compartida y la pone a disposición para su uso.

GetProcAddress y dlsym encuentra la dirección del símbolo. Por ejemplo:

HMODULE shared_lib = LoadLibrary("asdf.dll");
void *symbol = GetProcAddress("Foo");
// symbol is 0x12341234

En Windows, hay un archivo .lib para usar .dll. Cuando se enlaza a este archivo .lib, no es necesario llamar a LoadLibrary y GetProcAddress, y simplemente usar la biblioteca compartida funcionan como si fueran funciones "normales". ¿Cómo puede funcionar?

De hecho, el .lib contiene una información de importación . Es así:

void *Foo; // please put the address of Foo there
void *Bar; // please put the address of Bar there

Cuando el sistema operativo carga su programa (estrictamente hablando, su módulo ), el sistema operativo realiza LoadLibrary y GetProcAddress automáticamente.

Y si escribes código como Foo();, el compilador lo convierte en (*Foo)(); automáticamente. Así que puedes usarlas como si fueran funciones "normales".

 0
Author: ikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-04 11:23:34