Explicación detallada del empaquetado de la biblioteca de dependencias de aplicaciones Linux integradas

rootfs construye la biblioteca de tiempo de ejecución

Cuando desarrollamos un programa de microcontrolador sin sistema, el compilador vinculará las bibliotecas de las que depende nuestro programa (como la biblioteca Math) a nuestro programa, y ​​el firmware final solo tendrá un archivo .hex, que es un enlace estático.

Un microcontrolador sin sistema solo puede ejecutar un programa, por lo que no hay problema en vincular las bibliotecas de las que depende el programa directamente al programa. Sin embargo, se pueden ejecutar varias aplicaciones en un sistema Linux. Si la biblioteca dependiente está directamente vinculada al programa, esto hará que cada aplicación contenga una biblioteca matemática.

Pero, de hecho, la biblioteca Math de cada programa es la misma, por lo que la mejor manera es colocar la biblioteca Math en el sistema de archivos raíz de Linux y dejar que los programas requeridos carguen Math en el sistema de archivos raíz, de modo que cada programa comparta una Biblioteca de matemáticas. Puede evitar desperdiciar espacio duplicando bibliotecas de matemáticas. Esto es vinculación dinámica.

1. Introducción

Los amigos que han ejecutado aplicaciones en Linux integrado se han encontrado más o menos con el problema de que el terminal genera "-sh ./xxx: no encontrado" al iniciar la aplicación en el terminal de Linux. Esta es una dependencia dinámica de la aplicación. Causada por falta bibliotecas, la forma de verificar este problema es usar compilación estática para compilar la aplicación (la compilación estática empaquetará las bibliotecas de las que depende la aplicación y la aplicación en sí, por lo que la aplicación compilada estáticamente es muy grande, por lo que generalmente no se usa) .

Cuando el sistema Linux carece de bibliotecas dependientes, puede usar la compilación estática o agregar los archivos de biblioteca de los que depende el programa en el sistema de archivos raíz de Linux. La compilación estática solo requiere agregar opciones de compilación -statica gcc. Este artículo utiliza principalmente la biblioteca C como ejemplo. Para hablar sobre la biblioteca dinámica que falta, Importar a Linux y qué tipo de biblioteca dinámica se debe importar.

2. directorio lib

En el sistema Linux, la biblioteca compartida de la aplicación y la biblioteca de enlaces dinámicos dependientes se almacenan en el /libdirectorio rootfs. Lo mismo ocurre con los sistemas Linux integrados, por lo que si la aplicación se basa en una biblioteca de enlaces dinámicos, entonces la biblioteca de enlaces dinámicos correspondiente debe importarse a este directorio. Si el directorio no existe, debemos crearlo /libmanualmente /lib( es un directorio requerido, generalmente existe), el método de importación es muy simple, simplemente copie y pegue desde otros lugares aquí.

3. Encuentra archivos de la biblioteca

Ahora que sabemos dónde deben ubicarse las bibliotecas dependientes del programa, ¿de dónde deben provenir los archivos de la biblioteca? ¿Sabes de cuántas partes consta una cadena de herramientas de compilación cruzada? Consta de tres partes: compilador cruzado (gcc, g++, ld), biblioteca C de ARM (Glibc) y herramientas binarias (es decir, Binutils). Entonces, el archivo de la biblioteca se obtiene de la biblioteca C del compilador cruzado, busque el directorio donde se encuentra la cadena de herramientas de compilación cruzada y vea en qué directorio colocó el compilador cruzado al configurar el entorno de compilación cruzada.

.soPor ejemplo, mi cadena de herramientas se encuentra en el directorio /usr/local/arm. Puede ver muchos archivos de biblioteca con sufijos en el directorio arm-linux-gnueabi/libc/lib debajo del directorio arm.

zhbi98@ubuntu:/usr/local/arm/arm-linux-gnueabi/libc/lib$ ls
debug                    libgfortran.a           libnss_nisplus.so.2
ld-2.25.so               libgfortran.so          libnss_nis.so.2
ld-linux.so.3            libgfortran.so.4        libpcprofile.so
ldscripts                libgfortran.so.4.0.0    libpthread-2.25.so
libanl-2.25.so           libgfortran.spec        libpthread.so.0
libanl.so.1              libgomp.a               libresolv-2.25.so
libasan.so               libgomp.so.1.0.0        librt.so.1
libasan.so.4             libgomp.spec            libsanitizer.spec
libatomic.so.1           libitm.so.1.0.0         libssp.so
libatomic.so.1.2.0       libitm.spec             libssp.so.0
libBrokenLocale-2.25.so  libm-2.25.so            libssp.so.0.0.0
libc-2.25.so             libm.so.6               libstdc++fs.a
...
...
...

Si el espacio rootfs de su sistema Linux incorporado es lo suficientemente grande, puede importar todos los archivos en el directorio de la cadena de herramientas .soa Linux incorporado. Debido a que el programa se compila utilizando una cadena de herramientas cruzada y todas las bibliotecas dependientes provienen del directorio de la cadena de herramientas, definitivamente no faltarán bibliotecas. Pero no se recomienda hacer esto, porque hay muchos archivos de biblioteca que es posible que no usemos, lo que provoca una pérdida de espacio y los rootfs de Linux integrados están desordenados, por lo que es necesario cortarlos, especialmente cuando los rootfs de Linux integrados no tienen suficiente. espacio.

4. Recorte de archivos de biblioteca

¿La aplicación requiere todos los archivos en el directorio de la biblioteca C de la cadena de herramientas? No, analicemos la composición del contenido del directorio de la biblioteca C en la cadena de herramientas de compilación cruzada de ARM, que se divide en cinco categorías:

(1) Archivo objeto: .ocon sufijo, por ejemplo libasan_preinit.o, utilizado para archivos ejecutables de enlace GCC.

(2) Biblioteca estática: .acon el sufijo, por ejemplo libstdc++.a, contiene código objeto compilado, que se puede empaquetar en el archivo ejecutable final junto con la aplicación durante la vinculación.

(3) Biblioteca compartida: .socon el sufijo, por ejemplo libc.so.6, también se denomina biblioteca de vínculos dinámicos. Una biblioteca compartida es un código objeto compilado que se puede cargar dinámicamente en la memoria en tiempo de ejecución. Varias aplicaciones pueden compartir la misma biblioteca compartida, ahorrando recursos del sistema y espacio de memoria.

(4) Cargador de biblioteca de vínculos dinámicos: por ejemplo ld-linux.so.3, una aplicación que se basa en vínculos dinámicos no vinculará la biblioteca C a la aplicación. Por lo tanto, cuando la aplicación se ejecuta en algún código que requiere la biblioteca C, Linux debe ubicar y luego cargar la dependencias de la aplicación Todos los archivos de la biblioteca dinámica, y este trabajo lo completa el cargador de la biblioteca de enlaces dinámicos.

(5) Otros documentos: libgomp.specp.e.

Por lo tanto, los únicos dos tipos de archivos en los que se centran las aplicaciones de enlace dinámico son (3) y (4), por lo que solo necesita importar estos dos tipos de archivos a Linux incorporado, eliminando así algunos archivos inútiles.

5. Recorte en profundidad de archivos de biblioteca

De hecho, los dos tipos de archivos en las subsecciones (3) y (4) se pueden recortar aún más. Las bibliotecas que se deben importar a Linux integrado dependen completamente de qué funciones de biblioteca utiliza la aplicación. Se cargan las bibliotecas utilizadas y las bibliotecas de enlaces dinámicos correspondientes. Simplemente impórtelas a Linux integrado. ¿Cómo saber de qué archivos de biblioteca depende la aplicación y el cargador de biblioteca de enlaces correspondiente?Continuar analizando.

5.1 Ver bibliotecas de dependencia de aplicaciones

Antes de importar las bibliotecas dependientes de un programa a un sistema Linux integrado, necesita saber de qué bibliotecas C depende el programa. Para los programas escritos enteramente por nosotros mismos, sabemos exactamente qué bibliotecas C se utilizan, pero si el programa hace referencia a un código abierto proyecto, ¿cómo debemos determinar el proyecto de código abierto en sí? ¿En qué bibliotecas C confía? ¿Puede encontrarlas en el código fuente de los proyectos de código abierto? Este es un método, pero lleva demasiado tiempo. De hecho, el sistema Linux proporciona las herramientas correspondientes. Estas herramientas pueden enumerarnos rápidamente los nombres de todas las bibliotecas dependientes de la aplicación. En el sistema Linux, el sufijo de la biblioteca de enlace dinámico termina .socon de.

(1) La herramienta readelf es proporcionada por el conjunto de herramientas Binutils de la cadena de herramientas de compilación cruzada ARM. El método de uso es arm-linux-gnueabi-readelf -a [nombre de archivo], por ejemplo, arm-linux-gnueabi-readelf -Se puede ver un mian.main depende de las dos bibliotecas de enlaces dinámicos libm.so.6 y libc.so.6.

$ arm-linux-gnueabi-readelf -a main
...
...
0x00000001 (NEEDED)                     Shared library: [libm.so.6]
0x00000001 (NEEDED)                     Shared library: [libc.so.6]
...
...

Si desea que readelf solo genere información sobre la parte de la biblioteca dependiente, puede agregar | grep "Shared"el carácter de barra vertical al comando para filtrar la información relacionada "Compartida", de la siguiente manera.

$ arm-linux-gnueabi-readelf -a main | grep "Shared"
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

(2) herramienta objdump, esta herramienta se proporciona en el conjunto de herramientas Binutils de la cadena de herramientas cruzadas ARM. El método de uso es arm-linux-gnueabi-objdump -x [nombre de archivo], por ejemplo, arm-linux-gnueabi- Se puede ver que objdump -x main depende de las dos bibliotecas de enlaces dinámicos libm.so.6 y libc.so.6.

$ arm-linux-gnueabi-objdump -x main
...
...
Dynamic Section:
  NEEDED               libm.so.6
  NEEDED               libc.so.6
...
...

Si desea que objdump solo genere información sobre bibliotecas dependientes, puede agregar | grep NEEDEDel carácter de barra vertical al comando para filtrar la información relacionada NECESARIA, de la siguiente manera.

$ arm-linux-gnueabi-objdump -x main | grep NEEDED
  NEEDED               libm.so.6
  NEEDED               libc.so.6

(3) comando ldd, Linux proporciona el comando ldd. Utilice ldd [nombre de archivo] en la terminal de Linux para ver la biblioteca de enlaces dinámicos requerida para el archivo elf especificado, así como el cargador de bibliotecas de enlaces dinámicos. Por ejemplo, ldd mian puede Consulte las dependencias principales: libm.so.6 y libc.so.6 están instalados, así como el cargador de bibliotecas de vínculos dinámicos ld-linux.so.3.

$ ldd mian
checking sub-depends for 'not found'
        libm.so.6 => not found (0x00000000)
        libc.so.6 => not found (0x00000000)
        /lib/ld-linux.so.3 => /lib/ld-linux.so.3 (0x00000000)

A través de los tres métodos anteriores, puede conocer las bibliotecas dependientes específicas de la aplicación, por lo que estas bibliotecas dependientes enumeradas deben importarse a Linux integrado.

5.2 Bibliotecas dinámicas y enlaces simbólicos

En los sistemas Linux, una biblioteca de vínculos dinámicos contiene tres partes: la biblioteca de vínculos compartidos real, el vínculo simbólico a la revisión principal y el vínculo simbólico independiente de la versión.

(1) La biblioteca de enlaces compartidos real es una biblioteca de enlaces dinámicos que en realidad se puede vincular a la aplicación, y los números de versión generalmente se usan para nombrar e identificar sus diferentes versiones. El formato de nomenclatura es, por ejemplo, libm-2.25.so lib[库名称]-[库版本].so.

(2) El enlace simbólico de la revisión principal no es una biblioteca de enlaces compartidos real, sino un (1)enlace suave de la biblioteca de enlaces compartidos real, y generalmente se usa un número de versión principal para nombrar e identificar sus diferentes versiones. El formato de nomenclatura es lib[库名称].so.[主修订版本号], Por ejemplo libm.so.6.

(3) El enlace simbólico independiente de la versión no es una biblioteca de enlaces compartidos real, sino un (2)enlace suave de la revisión principal. Por razones de compatibilidad, no se distingue la versión (como un nombre de biblioteca común al compilar el programa), por lo que el nombre no incluye el número de versión, el formato de denominación es lib[库名称].so, por ejemplo, libm.so.

5.3 Ver enlaces simbólicos de bibliotecas dinámicas

Utilice lsel comando con opciones adicionales -lpara mostrar detalles del archivo, incluidos enlaces simbólicos en formato largo. Por ejemplo, si ve el enlace simbólico de la biblioteca dinámica libm.so.6, puede ver libm.so.6 -> libm-2.25. entonces (es decir, libm.so .6 es un enlace suave a libm-2.25.so).

$ ls -l libm.so.6
lrwxrwxrwx 1 root root 12 Apr 15 00:13 libm.so.6 -> libm-2.25.so

Por lo tanto, la biblioteca de enlaces compartidos real debe importarse a Linux integrado.

5.4 Resumen

A través del análisis anterior, solo necesitamos combinar los elementos que componen la biblioteca de enlaces dinámicos (1 enlace simbólico de revisión principal y 1 biblioteca de enlaces compartidos real) y los elementos que componen el cargador de biblioteca de enlaces dinámicos (1 enlace simbólico de revisión principal). y 1 cargador de biblioteca de enlaces real) se pueden importar a Linux integrado.

Por ejemplo, para importar una biblioteca matemática, necesita combinar los elementos que componen la biblioteca matemática (libm.so.6 y libm-2.25.so) y los elementos que componen el cargador de biblioteca de enlace dinámico (ld-linux. so.3 y ld-2.25 .so) en Linux integrado.

Nota: Todas las bibliotecas de vínculos dinámicos comparten un cargador de bibliotecas de vínculos dinámicos, por lo que no importa qué biblioteca se importe, se debe importar el cargador de bibliotecas.

6. Principio de compatibilidad de biblioteca dinámica

Como se mencionó anteriormente, los enlaces simbólicos también son un componente de las bibliotecas de enlaces dinámicos. Tomemos la biblioteca matemática libm como ejemplo para ilustrar el principio de Linux que utiliza enlaces simbólicos para lograr la compatibilidad de las bibliotecas de enlaces dinámicos.

Por ejemplo, libm.so.6 es un enlace simbólico que apunta a la biblioteca de enlaces compartidos libm-2.25.so. Esto se debe a que en los sistemas Linux, las bibliotecas de enlaces dinámicos suelen utilizar números de versión para identificar sus diferentes versiones, libm-2.25. entonces representa la versión 2.25 de la biblioteca libm.

Y libm.so.6 es un enlace simbólico de compatibilidad que siempre apuntará a la última versión de la biblioteca libm instalada en el sistema (por ejemplo, siempre apunta a libm-2.25.so) para que las aplicaciones puedan cambiar entre diferentes versiones de libm y Compatible, este método puede garantizar que no sea necesario volver a compilar la aplicación al actualizar la versión de la biblioteca y puede garantizar que la aplicación pueda ejecutarse normalmente en diferentes sistemas.

Ejemplo

Ahora use un ejemplo para ilustrar cómo la aplicación ubica y se vincula a la biblioteca de vínculos dinámicos. Tomemos como ejemplo la compilación y ejecución de la aplicación principal.

Por ejemplo, cuando usamos gcc main.c -o main -lm para compilar el programa principal, gcc agregará lib a m de acuerdo con la opción -lm y usará .so como sufijo para obtener un enlace simbólico libm independiente de la versión. entonces. Por lo tanto, libm.so.6 se encuentra a lo largo del enlace simbólico independiente de la versión (libm.so -> libm.so.6) y se registra en el encabezado ELF de main para indicar que main necesita usar el archivo de biblioteca representado por libm. so.6 Funciones de biblioteca en la biblioteca de matemáticas.

Cuando Linux ejecuta main, el cargador de biblioteca de enlace dinámico encontrará el registro libm.so.6 del encabezado ELF de main y luego seguirá el enlace simbólico de la revisión principal (libm.so.6 -> libm-2.3. 6.so) Busque la biblioteca de enlaces compartidos libm-2.3.6.so y vincúlela dinámicamente con main.

Se puede ver que el enlace simbólico independiente de la versión es para el compilador, el enlace simbólico de revisión principal es para el cargador de bibliotecas de enlaces dinámicos y la biblioteca de enlaces compartidos real es para la aplicación.

Ver en detalle:

https://blog.csdn.net/linux_0416/article/details/79640199

https://blog.csdn.net/wsp_1138886114/article/details/128110849

Cargador de biblioteca de enlaces de biblioteca dinámica ld-linux.so.3

https://blog.csdn.net/elfprincexu/article/details/51701242

Supongo que te gusta

Origin blog.csdn.net/jf_52001760/article/details/131622539
Recomendado
Clasificación