uso una qué que programación programacion llama librería librerias libreria lenguaje las files externa ejemplos clase caracteristicas bibliotecas biblioteca language-agnostic linker loader

language-agnostic - una - uso de librerias en programacion



¿Por qué son diferentes las bibliotecas enlazables estáticas y dinámicas? (6)

Si ambos contienen código compilado, ¿por qué no podemos cargar los archivos "estáticos" en tiempo de ejecución y por qué no podemos vincular con las bibliotecas dinámicas en el momento de la compilación? ¿Por qué hay una necesidad de formatos separados para contener el código "independiente"? ¿Qué necesita ser almacenado en cualquiera que justifique la diferencia?


El código en un archivo de objeto no está vinculado. Contiene referencias implícitas a funciones externas que aún no se han resuelto.

Cuando los archivos de objetos están vinculados para crear una DLL, el vinculador examina todas las referencias externas y encuentra otras bibliotecas (estáticas o dinámicas) que pueden satisfacerlas. Una referencia a un nombre en una biblioteca estática se resuelve al incluir el cuerpo de esa función (o lo que sea) en la DLL. Si se refiere a una biblioteca dinámica, el nombre de la DLL y la función a la que se hace referencia se incluyen en la DLL.

En última instancia, no hay ninguna razón por la cual este debería ser el caso. En teoría, podría escribir el cargador para hacer todo esto cada vez que cargó un archivo. Básicamente es solo una optimización: el enlazador realiza las partes relativamente lentas del trabajo. Las referencias a las DLL se quedan, pero se resuelven hasta el punto de que es bastante rápido para que el cargador encuentre y cargue el archivo de destino (si es necesario) y resuelva las funciones a las que se hace referencia. Cuando el enlazador está haciendo su trabajo, hace mucho más escaneando largas listas de definiciones para encontrar las que le interesan, lo que es bastante más lento.


Las bibliotecas estáticas son bibliotecas verdaderas en el sentido de que contienen una biblioteca de archivos de objetos. Cada archivo de objeto a menudo se crea a partir de un único archivo de origen y contiene código de máquina, así como información sobre los datos requeridos para el código. Durante el paso del enlace, el vinculador seleccionará los archivos de objeto necesarios y los combinará en un archivo ejecutable.

Una parte importante del código de máquina es que saltos, llamadas y punteros de datos deberán contener direcciones de memoria reales. Sin embargo, si un archivo objeto necesita llamar a otra función en otro archivo objeto, solo puede referirse a esa función utilizando un símbolo. Cuando el vinculador combina los archivos objeto en código ejecutable, las referencias de símbolos se resuelven y se convierten en direcciones de memoria real.

Una biblioteca dinámica es un código ejecutable que se puede cargar en la memoria y ejecutar de inmediato. En algunos sistemas operativos puede haber un paso adicional en el que el código se vuelve a establecer moviendo el código ejecutable a otra ubicación y esto requiere que todas las direcciones absolutas dentro del código se desplacen en una cantidad fija. Esta operación es mucho más rápida que la combinación de archivos de objeto y símbolos de resolución realizados por el vinculador.

En resumen:

  • Las bibliotecas estáticas contienen fragmentos de código ejecutable que usa símbolos para referirse a otras partes del código ejecutable
  • Las bibliotecas dinámicas (y los ejecutables) contienen código ejecutable ahora colocado en ubicaciones fijas que permiten que los símbolos se reemplacen con direcciones de memoria reales

Si alguna vez ha intentado vincular un proyecto de tamaño razonable, habrá notado que se necesita una cantidad de tiempo no trivial, probablemente más de lo que le gustaría esperar para iniciar una aplicación. Eso explica por qué no puede ejecutar bibliotecas estáticas. Y las bibliotecas dinámicas se han optimizado y eliminado para que no contengan nada, excepto el código ejecutable, lo que las hace inadecuadas para su uso como bibliotecas estáticas.


Nota: La siguiente respuesta no es independiente de la plataforma, sino específica para los sistemas basados ​​en ELF y algunos otros similares. Alguien más puede completar los detalles de otros sistemas.

¿Qué es una biblioteca estática?

Una biblioteca estática es una colección de archivos *.o en un archivo. Cada archivo puede contener referencias a símbolos indefinidos que deben ser resueltos por el vinculador, por ejemplo, su biblioteca podría tener una referencia a printf . La biblioteca no proporciona ninguna indicación acerca de dónde se encontrará printf , se espera que el vinculador lo encuentre en una de las otras bibliotecas a las que se le pide vincular.

Supongamos que su biblioteca contiene el siguiente código:

read_png.o write_png.o read_jpg.o write_jpg.o resize_image.o handle_error.o

Si una aplicación solo usa read_png y write_png , las otras partes del código no se cargarán en el ejecutable (excepto handle_error , que se llama desde read_png y write_png ).

No podemos cargar una biblioteca estática en tiempo de ejecución porque:

  • El vinculador no sabe dónde encontrar objetos externos, por ejemplo, printf .

  • Sería lento Las bibliotecas dinámicas están optimizadas para una carga rápida.

  • Las bibliotecas estáticas no tienen ningún concepto de espacios de nombres. No puedo definir mi propio handle_error porque entraría en conflicto con la definición de la biblioteca.

¿Qué es una biblioteca dinámica?

Una biblioteca dinámica, en sistemas ELF, es el mismo tipo de objeto que un ejecutable. También exporta más símbolos, un ejecutable solo necesita exportar _start . Las bibliotecas dinámicas están optimizadas, por lo que todo se puede asignar directamente a la memoria.

Si tiene una llamada para printf en su biblioteca dinámica, existen algunos requisitos adicionales más allá de los requisitos para bibliotecas estáticas:

  • Debes especificar qué biblioteca tiene printf .

  • Debe llamar a la función de una manera especial que permita al vinculador insertar la dirección para printf . En una biblioteca estática, el enlazador solo puede modificar su código e insertar la dirección directamente, pero esto no es posible con las bibliotecas compartidas.

No queremos utilizar bibliotecas dinámicas para vincular estáticamente porque:

  • No podemos vincular solo una parte de una biblioteca dinámica. Incluso si nuestro ejecutable nunca llama a read_jpg , se incluye porque las bibliotecas dinámicas son todo o nada.

  • La sobrecarga adicional para llamadas de funciones es un desperdicio, incluso si es pequeño.

Resumen

La compilación se ve así:

Source ==compile==> Object ==link==> Executable / Shared Library

Una biblioteca estática es un archivo lleno de objetos que aún no se han vinculado. Hay mucho trabajo por hacer.

Una biblioteca compartida es un producto final vinculado, listo para ser cargado en la memoria.

Las bibliotecas estáticas se inventaron primero. Si ambos fueron inventados al mismo tiempo, es posible que sean mucho más similares.


No hay una razón fundamental por la que no pueda usar los archivos de la biblioteca estática ( .a ) como bibliotecas dinámicas, cargándolos y vinculándolos al inicio del programa o incluso dinámicamente en el tiempo de ejecución. Sin embargo, no han sido especialmente compilados y preparados para ejecutar mapas de memoria en una dirección arbitraria (¡ni siquiera la alineación es necesariamente correcta!), Por lo que el código del cargador tendría que asignar memoria, leer los objetos necesarios de los archivos .a en esta memoria, y realizar modificaciones importantes en él. Y, por supuesto, nada de este recuerdo sería compartible. Por lo tanto, es probablemente una muy mala idea ...


Static lib == tarball mientras que dinámica == imagen contigua parcialmente enlazada

Una biblioteca estática es solo un tarball 1 de archivos .o or .obj`. Cuando se vincula un ejecutable, los módulos referenciados (y los que hacen referencia, y luego los que hacen referencia, y luego ... etc) se copian de la biblioteca estática y se insertan al final del programa principal. Todo esto está paginado en la memoria como un único "objeto" del sistema operativo.

Una biblioteca dinámica simplemente toma todos los elementos de la biblioteca estática, los vincula (resolviendo relaciones intramuros) y luego los mapea en la memoria. (La búsqueda de demanda puede hacer posible la presencia de memoria parcial.) Al iniciar programas dinámicos se necesita cierta cantidad de manipulación para conectar el programa principal (que se vinculará "estáticamente" dentro de sus propios módulos) a la biblioteca que se comparte. todo el sistema. A veces, este violín se retrasa por elemento de vinculación hasta que se realiza una llamada determinada. En un barrido muy amplio y excesivamente conceptual, uno podría categorizar los enlaces estáticos como cargas ansiosas y dinámicas como la carga diferida .

Hay ventajas y desventajas con bibliotecas estáticas.

No hay infierno de DLL (también conocido como infierno de dependencia )
Huella de memoria mucho más pequeña para pequeñas mezclas de proceso en tiempo de ejecución
- Huella de memoria mucho mayor para grandes mezclas de procesos en tiempo de ejecución de programas dispares
- No se puede compartir ninguna memoria de código de biblioteca entre los procesos, excepto cuando ejecutan el mismo programa
- Un gran conjunto de programas (como huellas de Linux / Windows / Mac) ocupan mucho espacio ya que printf et al se duplican una y otra vez en cada imagen
- Es difícil, si no imposible, reparar los errores de seguridad que se originan en las bibliotecas
- Es difícil, si no imposible, actualizar una biblioteca solo
Es difícil, si no imposible, actualizar una biblioteca solo y romper su programa

1. En realidad, no están en formato tar (1) , pero está relacionado.