【iOS】Enlazador dinámico

Referencia: Entendiendo dyld: el enlazador dinámico

Introducción a dyld

dyld (Dynamic Linker) es el vinculador dinámico en sistemas macOS e iOS, es el componente responsable de cargar y vincular bibliotecas dinámicas compartidas (dylib) o archivos ejecutables en tiempo de ejecución. En sistemas macOS, dyld se encuentra en D/usr/lib/dyld.

dirección del código fuente de dyld

valor 2

dyld 2 (Dynamic Linker 2) es el enlazador dinámico de segunda generación en sistemas macOS e iOS. Se trata de una versión evolucionada del dyld 1 de la generación anterior, que ha sido mejorado y optimizado en términos de rendimiento, funcionalidad y seguridad. dyld 2 es el principal responsable de cargar y vincular componentes de bibliotecas compartidas dinámicas o archivos ejecutables en tiempo de ejecución y permitir que el programa se ejecute correctamente.

Estas son algunas de las características y mejoras clave en dyld 2:

  • Tiene soporte correcto para la semántica del inicializador de C++, extiende el formato Mach-O y actualiza dyld para un soporte eficiente de la biblioteca C++.
  • Admite más arquitecturas y plataformas.
    Desde el lanzamiento de dyld 2.0 en Power PC, se han agregado x86, x86 64 arm, arm64 y otras arquitecturas, compatibles con las plataformas iOS, tvOS y watchOS.
  • La seguridad se mejora de varias maneras.
    • Codiseño: firma de código. Para mejorar la seguridad de las aplicaciones, dyld 2 admite la verificación de firmas de código de aplicaciones y bibliotecas compartidas para garantizar que no hayan sido manipuladas ni modificadas maliciosamente.
    • ASLR: la configuración del espacio de direcciones de aleatorización del diseño del espacio de direcciones se carga aleatoriamente.
    • Comprobación de límites: se agregaron importantes capacidades de verificación de límites a muchos contenidos en el encabezado Mach-O para evitar la inyección de datos binarios maliciosos.
  • Compatibilidad con el simulador: dyld 2 proporciona un mejor rendimiento y compatibilidad funcional en el simulador de iOS, lo que facilita a los desarrolladores la depuración y prueba de aplicaciones en el simulador.
  • Mejore el rendimiento: utilice tecnología de caché compartida para reemplazar completamente el enlace previo.
  • Carga incremental: dyld 2 admite la carga incremental (carga incremental), es decir, cuando se inicia la aplicación, solo se cargan las bibliotecas y símbolos compartidos necesarios en lugar de cargar todas las bibliotecas dinámicas a la vez. Esto puede reducir aún más el tiempo de inicio y el uso de memoria.
  • Carga simultánea: dyld 2 aprovecha al máximo los procesadores multinúcleo y admite la carga simultánea de bibliotecas dinámicas compartidas, acelerando así el proceso de vinculación dinámica.
  • Aislamiento de símbolos: para mejorar la seguridad, dyld 2 introdujo un mecanismo de aislamiento de símbolos. Aísla las tablas de símbolos de las bibliotecas compartidas para que los símbolos entre bibliotecas compartidas no se afecten entre sí, evitando así conflictos y fugas de símbolos.

Proceso de implementación

Insertar descripción de la imagen aquí

  1. Inicialización de dyld 2: una vez que dyld 2 se carga en la memoria, realizará algunas operaciones de inicialización y estará listo para realizar tareas de enlace dinámico. El código principal es dyldbootstrap::starty luego se ejecuta dyld::_main . dyld::_mainHay mucho código, que es la parte central de la carga de dyld;
  2. Verifique y prepare el entorno, como obtener la ruta binaria, verificar las variables de entorno, analizar el binario principal image headey otra información;
  3. Cree una instancia del binario principal image loadery verifique si las versiones del binario principal y dyld coinciden;
  4. Compruebe shared cachesi se ha mapeado; de lo contrario, realice map shared cachela operación primero;
  5. Marque DYLD_INSERT_LIBRARIES, si corresponde, cargue la biblioteca dinámica insertada (instanciación image loader);
  6. Realizar operación de enlace. Este proceso es relativamente complicado. Todas las bibliotecas dinámicas dependientes se cargarán recursivamente primero (las bibliotecas dependientes se ordenarán y las dependientes siempre estarán al frente). Al mismo tiempo, se realizarán operaciones y vinculación de símbolos en esta etapa rebase. binding;
  7. Ejecute el método de inicialización. En esta etapa se ejecutarán los métodos Objective-C +loady C ;constructor
  8. Lea el segmento Mach-O LC_MAINpara obtener la dirección de entrada del programa y llame mainal método.

Cargar caché compartido

Debido a Foundationque también dependerá de algunas otras bibliotecas dinámicas, y estas bibliotecas dependientes dependerán de más bibliotecas, habrá muchos símbolos interdependientes y el tiempo de procesamiento será relativamente largo. El vinculador dinámico de este sistema utilizará la caché compartida, y la caché compartida está en formato /var/db/dyld/. Al cargar un archivo Mach-O, el vinculador dinámico primero verifica si hay un caché compartido. Cada proceso asignará estos cachés compartidos en su propio espacio de direcciones, lo que puede optimizar la velocidad de inicio de la aplicación.

La carga del caché compartido (Shared Cache)es una tecnología de optimización utilizada por dyld 2 en sistemas macOS e iOS para acelerar los enlaces dinámicos. La caché compartida es una colección de bibliotecas dinámicas pregenerada que contiene bibliotecas dinámicas compartidas comúnmente utilizadas por múltiples aplicaciones. Cuando se inicia la aplicación, dyld 2 puede cargar las bibliotecas dinámicas requeridas directamente desde el caché compartido sin tener que recargar las bibliotecas dinámicas una por una desde el disco, acelerando así el inicio de la aplicación.

El proceso de carga del caché compartido se puede resumir brevemente de la siguiente manera:

  1. Generar caché compartido: cuando el sistema está instalado o actualizado, el sistema operativo generará previamente un caché compartido, que contiene múltiples marcos y bibliotecas dinámicas compartidas del sistema de uso común. Este proceso generalmente ocurre cuando el dispositivo se inicia por primera vez, se actualiza el sistema operativo o el desarrollador vuelve a compilar las bibliotecas del sistema.
  2. Ruta de caché compartida: la caché compartida se guarda en el archivo del sistema y su ruta es, /System/Library/Caches/com.apple.dyld/dyld_shared_cache_x86_64(macOS)etc. /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64(iOS)La ruta específica variará según el dispositivo y la arquitectura.
  3. Inicio de la aplicación: cuando se inicia la aplicación, dyld 2 primero verificará si el caché compartido está disponible e intentará cargar el caché compartido.
  4. Cargue el caché compartido: si el caché compartido está disponible, dyld 2 asignará directamente el caché compartido a la memoria y establecerá una relación de enlace entre la biblioteca dinámica en el caché compartido y la aplicación.
  5. Resolución y reubicación de símbolos: después de cargar la caché compartida, dyld 2 realiza la resolución y reubicación de símbolos para asociar referencias de símbolos en la aplicación con direcciones de símbolos en la caché compartida.
  6. Vinculación de bibliotecas dinámicas: si la aplicación también depende de otras bibliotecas compartidas dinámicas que no están incluidas en el caché compartido, dyld 2 cargará estas bibliotecas compartidas dinámicas una por una según sea necesario y realizará la vinculación y la resolución de símbolos.
  7. Inicialización de la aplicación: una vez que se cargan todas las bibliotecas compartidas dinámicas y se completa la resolución de símbolos, dyld 2 comenzará a ejecutar las main()funciones de la aplicación, iniciando así oficialmente la ejecución de la aplicación.

Carga dinámica de biblioteca

Las bibliotecas compartidas vinculadas se dividen en bibliotecas estáticas y bibliotecas dinámicas:

  • La biblioteca estática es una biblioteca que está vinculada durante la compilación y debe vincularse al archivo Mach-O. Si necesita actualizarse, debe volver a compilarse y no se puede cargar ni actualizar dinámicamente;
  • Las bibliotecas dinámicas son bibliotecas vinculadas en tiempo de ejecución y la carga dinámica se puede lograr utilizando dyld.

El archivo Mach-O es un producto compilado y la biblioteca dinámica está vinculada en tiempo de ejecución y no participa en la compilación y vinculación del archivo Mach-O, por lo que el archivo Mach-O no contiene las definiciones de símbolos en la biblioteca dinámica. . Es decir, estos símbolos se mostrarán como "indefinidos", pero se registrarán sus nombres y las rutas de biblioteca correspondientes. Al importar una biblioteca dinámica a través de dlopen y dlsym en tiempo de ejecución, primero busque la biblioteca correspondiente de acuerdo con la ruta de la biblioteca registrada y luego busque la dirección de enlace a través del símbolo del nombre grabado.

dlopen cargará la biblioteca compartida en el espacio de direcciones del proceso en ejecución. La biblioteca compartida cargada también tendrá símbolos indefinidos, lo que provocará que se carguen más bibliotecas compartidas. dlopen también puede elegir si resolver todas las referencias inmediatamente o hacerlo de forma diferida. Después de que dlopen abre la biblioteca dinámica, devuelve un puntero de referencia. La función de dlsym es obtener la dirección de la función a través del puntero de la biblioteca dinámica y el símbolo de función devuelto por dlopen y luego usarlo.

Problemas con dyld 2

  • Parse mach-o headers puede utilizar encabezados de archivos Mach-O modificados para atacar.
  • Buscar dependencias puede usar @rpaths, que es la ruta de búsqueda. Al modificar estas rutas o insertar la biblioteca en la ubicación adecuada, el programa puede romperse;
  • Realizar búsquedas de símbolos La parte de búsqueda de símbolos, porque en una biblioteca determinada, los símbolos siempre estarán en el mismo desplazamiento en la biblioteca a menos que haya una actualización de software o se cambie la biblioteca en el disco;

valor 3

dyld 3 es un enlazador dinámico completamente nuevo que cambia completamente el concepto de enlace dinámico. WWDC-App Startup Time: Past, Present, and Future mencionó que en el sistema iOS 13, iOS adoptará completamente el nuevo dyld 3 para reemplazar la versión anterior de dyld 2. dyld 3 aporta considerables mejoras de rendimiento y reduce el tiempo de inicio de la aplicación. Debido a que dyld 3 es totalmente compatible con dyld 2 y la interfaz API es la misma, en la mayoría de los casos, los desarrolladores pueden realizar una transición sin problemas sin realizar adaptaciones adicionales.

Proceso de implementación

Insertar descripción de la imagen aquí

dyld 3 contiene estas tres partes:

  1. Analizador y compilador Mach-O fuera de proceso (analizador Mach-o fuera de proceso) Debido a los problemas existentes en dyld 2, dyld 3 utilizará el método de escritura anticipada para almacenar en caché los datos del resultado en un archivo para formar un cierre de lanzamiento (puede entenderse como un archivo de caché)
  2. El motor en proceso realiza el procesamiento de cierre de inicio (motor en proceso) para verificar si el "cierre de inicio" es correcto, asigna el dylib y ejecuta la función principal. En este punto, ya no es necesario analizar el encabezado mach-o y realizar la búsqueda de símbolos, lo que ahorra mucho tiempo.
  3. El cierre de inicio del programa del sistema del servicio de caché de cierre de inicio (caché de cierre de inicio) está integrado directamente en el caché compartido. Para aplicaciones de terceros, se generará cuando la aplicación se instale o actualice. Esto garantiza que el cierre de inicio sea siempre listo antes de abrir la APP.

La mayoría de los inicios de programas usan caché sin llamar a analizadores o compiladores Mach-O fuera de proceso, y los cierres de inicio son más simples que Mach-O. Son archivos mapeados en memoria y no requieren métodos complejos para analizarlos. Podemos simplemente validarlos, el objetivo es mejorar la velocidad

Problema de símbolos faltantes en dyld 3

dyld 2 adopta el método de carga de símbolos diferidos de forma predeterminada, pero en dyld 3, antes de que se inicie la aplicación, el resultado del análisis de símbolos ya está en el cierre de inicio, por lo que el símbolo diferido ya no es necesario. En este momento, si falta un símbolo, la aplicación se comportará de manera diferente: en el punto 2, la aplicación se bloqueará cuando se llame al símbolo que falta por primera vez; en el punto 3, el símbolo que falta hará que la aplicación se bloquee como tan pronto como se inicie.

Supongo que te gusta

Origin blog.csdn.net/m0_63852285/article/details/131892703
Recomendado
Clasificación