Linux, GNU GCC, ld, scripts de versión y el formato binario ELF - ¿Cómo funciona?

13

Estoy tratando de aprender más sobre el versionado de bibliotecas en Linux y cómo ponerlo a funcionar. Aquí está el contexto:

- Tengo dos versiones de una biblioteca dinámica que exponen el mismo conjunto de interfaces, digamos libsome1.soy libsome2.so.

- Una aplicación está vinculada contra libsome1.so.

- Esta aplicación utiliza libdl.sopara cargar dinámicamente otro módulo, por ejemplo libmagic.so.

- Ahora libmagic.soestá vinculado en contra libsome2.so. Obviamente, sin usar scripts de enlazador para ocultar símbolos libmagic.so, en tiempo de ejecución libsome2.sose resuelven todas las llamadas a las interfaces libsome1.so. Esto puede confirmarse comprobando el valor devuelto por libVersion()el valor de la macro LIB_VERSION.

- Entonces trato de compilar y vincular libmagic.socon un script vinculador que oculta todos los símbolos, excepto 3, que se definen libmagic.soy exportan. Esto funciona ... O al menos libVersion()y los LIB_VERSIONvalores coinciden (e informa la versión 2 no 1).

- Sin embargo, cuando algunas estructuras de datos se serializan en el disco, noté algo de corrupción. En el directorio de la aplicación, si elimino libsome1.soy creo un enlace suave en su lugar para señalar libsome2.so, todo funciona como se espera y no ocurre la misma corrupción.

No puedo evitar pensar que esto puede deberse a algún conflicto en la resolución de símbolos del enlazador en tiempo de ejecución. He intentado muchas cosas, como intentar vincular libsome2.sopara que todos los símbolos estén alineados symbol@@VER_2(lo cual todavía estoy confundido porque el comando nm -CD libsome2.sotodavía enumera símbolos como symboly no symbol@@VER_2) ... ¡Parece que nada funciona! ¡¡¡¡¡¡Ayuda!!!!!!

themoondothshine
fuente
Su último enfoque es con el que habría comenzado. Y estoy de acuerdo en que la corrupción es probablemente un símbolo de confusión. Lamentablemente no tengo una respuesta para ti.
RobotHumans
esto podría funcionar mejor en SO, aunque por cierto no lo entiendo lo suficiente como para estar seguro. márquelo si desea que lo traslademos.
xenoterracide
1
Pruebe las banderas RTLD_LOCALy RTLD_DEEPBINDdlopen en su aplicación. No tengo tiempo para probar esto ahora, pero debería funcionar según la página de manual.
stribika

Respuestas:

13

Esto no responde exactamente a su pregunta, pero ...

En primer lugar, ELF es la especificación utilizada por Linux para archivos ejecutables (programas), bibliotecas compartidas y también archivos de objetos que son los archivos intermedios que se encuentran al compilar software. Los archivos de objetos terminan en .o, las bibliotecas compartidas terminan en .so seguidas de cero o más dígitos separados por puntos, y los archivos ejecutables normalmente no tienen ninguna extensión.

Normalmente hay tres formas para nombrar una biblioteca compartida, la primera forma simplemente termina en .so. Por ejemplo, una biblioteca llamada readline se almacena en un archivo llamado libreadline.so y normalmente se encuentra debajo de / lib, / usr / lib o / usr / local / lib. Ese archivo se encuentra al compilar software con una opción como -lreadline. -l le dice al compilador que se vincule con la siguiente biblioteca. Debido a que las bibliotecas cambian de vez en cuando, puede volverse obsoleta, por lo que las bibliotecas incorporan algo llamado SONAME. El SONAME para readline podría verse como libreadline.so.2 para la segunda versión de la versión principal de libreadline. También puede haber muchas versiones menores de readline que sean compatibles y no requieran que se vuelva a compilar el software. Una versión menor de readline podría llamarse libreadline.so.2.14. Normalmente libreadline. así que es solo un enlace simbólico a la versión principal más reciente de readline, libreadline.so.2 en este caso. libreadline.so.2 también es un enlace simbólico a libreadline.so.2.14, que en realidad es el archivo que se está utilizando.

El SONAME de una biblioteca está incrustado dentro del archivo de la biblioteca. En algún lugar dentro del archivo libreadline.so.2.14 está la cadena libreadline.so.2. Cuando se compila un programa y se vincula con readline, buscará el archivo libreadline.so y leerá el SONAME incrustado en él. Más tarde, cuando el programa se ejecute realmente, cargará libreadline.so.2, no solo libreadline.so, ya que ese fue el SONAME que se leyó cuando se vinculó por primera vez. Esto permite que un sistema tenga múltiples versiones incompatibles de readline instaladas, y cada programa cargará la versión principal apropiada con la que se vinculó. Además, al actualizar readline, digamos, a 2.17, puedo instalar libreadline.so.2.17 junto con la biblioteca existente, y una vez que mueva el enlace simbólico libreadline.so.2 de libreadline.so.2.13 a libreadline.so.2.17,

pingüino359
fuente