2009-12-04 17 views
7

Deseo crear una biblioteca compartida que use funciones de una biblioteca estática de un tercero. Por ejemplo, foo y bar de libfoobar.a. Sé que mi aplicación principal también está usando foo y exportaré ese símbolo. Así que simplemente quiero vincular en bar para guardar el tamaño del código y dejar 'foo' sin resolver (ya que será proporcionado por la aplicación principal). Si incluyo libfoobar.a, el enlazador ld incluirá ambas funciones en mi biblioteca compartida. Si no incluyo libfoobar.a, mi biblioteca no tendrá acceso a la función bar porque la aplicación en sí no está enlazando en bar. Preguntas:Vinculación estática selectiva de funciones de biblioteca en biblioteca compartida

  • ¿Hay una manera de contar ld sólo a resolver ciertos símbolos en la construcción de la biblioteca compartida?
  • ¿Cómo convertir a libfoobar.a en una biblioteca compartida?
  • Extraiga el archivo que contiene la función bar desde libfoobar.a y especifique eso en la línea del enlazador?
  • No se preocupe, el cargador de tiempo de ejecución usará bar desde su aplicación para que no se cargue la copia de bar en la biblioteca compartida.

Respuesta

4

Los siguientes puntos tratan de responder a las preguntas que había que plantea:

  • ld no parece que le permite omitir la vinculación de ciertos símbolos de una biblioteca estática. El uso de --just-symbols o --undefined (o el comando de secuencia de comandos del enlazador EXTERN) no impedirá que ld vincule los símbolos.
  • Para convertir una biblioteca estática, libfoobar.a, en una responsabilidad compartida, libfoobar.so.1.0 y exportar todos los símbolos visibles. También puede usar --version-script y otros métodos para exportar solo un subconjunto de símbolos.

    ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive

  • Mejor es eliminar los miembros del archivo desde una copia de su biblioteca estática de lo que es para extraerlos porque puede haber dependencias internas que tienen que manejar. Por ejemplo, suponiendo que está exportando todos los símbolos, puede generar un archivo de mapa desde su ejecutable principal. A continuación, puede grep para todos los miembros de archivo que el archivo ejecutable extrajo de la copia de la biblioteca estática y eliminarlos de la copia. Entonces, cuando su DSO esté enlazando en la biblioteca estática, dejará los mismos símbolos sin resolver.

  • Es posible especificar su ejecutable principal como una biblioteca compartida para su DSO si compila el ejecutable con la opción --pie. Su DSO se vinculará primero a su ejecutable si precedió a la biblioteca estática en el comando de enlace. La advertencia es que el ejecutable principal debe estar disponible a través de LD_LIBRARY_PATH o -rpath. Además, el uso de strace revela que, dado que el ejecutable es una dependencia de su biblioteca, se carga de nuevo cuando se carga su DSO.

    ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a

  • El enlazador dinámico utilizará la versión del ejecutable del foo primero a menos que llame dlopen() con la bandera RTLD_DEEPBIND. El uso de strace revela que todo el DSO está mapeado en el archivo mmap2() en la memoria. Sin embargo, Wikipedia afirma que para mmap "las lecturas reales del disco se realizan de forma" floja ", después de acceder a una ubicación específica". Si esto es cierto, no se cargará el duplicado foo. Tenga en cuenta que la anulación solo ocurre si su DSO exportó la función foo. De lo contrario, la función foo que estaba vinculada estáticamente a su DSO se usará cada vez que su DSO llame al foo.

En conclusión, si mmap() utiliza una lectura perezosa, entonces la mejor solución es vincular su DSO de la manera normal y dejar que el enlazador dinámico y Linux se ocupan del resto.

1

No soy el mayor experto en bibliotecas compartidas, ¡así que podría estar equivocado aquí!

Si estoy acertando acerca de lo que está tratando de hacer, simplemente enlace su lib compartido contra libc.so. No desea una copia adicional de sscanf incrustado en su biblioteca.

He respondido a sus preguntas antes de que hubiera descubierto a qué se dirigía, en caso de que le interesen las respuestas.

¿Hay alguna manera de decirle a ld que solo resuelva ciertos símbolos al compilar la biblioteca compartida?

solo extern, no estático, las funciones y variables van en la tabla de símbolos de la biblioteca compartida.

Cuando construye su biblioteca compartida, los símbolos que no se encuentren en los objetos en la línea de comando del enlazador permanecerán sin resolver. Si el enlazador se queja de eso, es probable que deba vincular su lib compartida con libc compartida. Puede tener librerías compartidas que dependan de otras librerías compartidas, y ld.so puede ocuparse de las cadenas de dependencia.

Si tuviera más representantes, le preguntaría esto como un comentario: ¿Tiene una versión personalizada de sprintf/sscanf, o estaría bien que su biblioteca compartida use la implementación en -lc? Si -lc está bien, entonces mi respuesta probablemente resuelva tu problema. Si no es así, entonces necesita construir su biblioteca compartida de objetos que solo tienen las funciones que necesita. es decir, no lo vincule con /usr/lib/libc.a.

Tal vez estoy siendo confundidos por su

libc.a (no en realidad el "verdadero" libc) línea. /usr/lib/libc.a es realmente glibc (en Linux). Es una copia estáticamente vinculada del mismo código en libc.so. A menos que estés hablando de tu propia libc.a (que es lo que estaba pensando al principio) ...

¿Quieres convertir libc.a a una biblioteca compartida? Probablemente pueda, pero no lo haga, porque probablemente no se haya compilado como código de posición independiente, por lo que sería necesario realizar muchas reubicaciones por ld.so en tiempo de ejecución.

Extraiga sscanf de libc.a y especifique eso en la línea del enlazador?

Puede ser posible. ar t /usr/lib/libc.a para enumerar los contenidos. (los argumentos de ar son similares a tar. tar era ar para las cintas ... Old school Unix aquí.) Probablemente no sea tan fácil, porque sscanf probablemente dependa de símbolos en otros archivos .o en .a.

+0

Disculpe la confusión de libc. Simplemente quise decir cualquier biblioteca estática de terceros y usé libc como ejemplo. Voy a modificar mi pregunta para aclarar esto. – KlaxSmashing

1

Respondiendo a su pregunta revisada más clara.

Tenga en cuenta que normalmente el objetivo de una biblioteca compartida es que varios programas pueden enlazarse con ella. Por lo tanto, su optimización del uso del símbolo del programa principal para una función que necesita solo funcionará si el programa principal siempre proporciona ese símbolo (mediante una lib estática o de otro modo). Esto no es generalmente lo que la gente quiere hacer.

Si solo son un par de funciones pequeñas, probablemente debería dejarlo. Probablemente termines con dos copias del código para las funciones, una en tu shlib y otra en el programa principal. Si son pequeños (o al menos no enormes), o no son llamados con frecuencia y no son críticos para el rendimiento, entonces el tamaño de código/I-caché de tener dos copias no es algo de lo que preocuparse. (Traducción: No sé cómo evitarlo en mi cabeza, así que es posible que no me tome el tiempo de buscarlo y crear un Makefile más complejo para evitarlo).

Ver mi otra respuesta para algunos comentarios sobre jugar con ar para extraer cosas de una biblioteca estática. resumen: probablemente no trivial, ya que no conoce las dependencias entre los diversos archivos .o en .a.

Es posible hacer lo que espera haciendo que su biblioteca compartida exporte los símbolos que extrae de la biblioteca estática. Luego, cuando vincule la aplicación principal, coloque su biblioteca compartida antes de la lib estática en la línea de comando del enlazador. Encontrará "foo" en su shlib, y usará esa copia (si es posible este truco de reexportación), pero para "bar" tendrá que incluir una copia de la lib estática.

ld --export-dynamic puede ser lo que necesita para exportar todos los símbolos en la tabla de símbolos dinámicos. Trata eso. Y busque "exportar" en la página de documentación/manual. "exportar" es la jerga para hacer que un símbolo sea visible en una biblioteca. --export-all-symbols está en la sección i386 PE (Windows DLL), de lo contrario, probablemente sea suficiente.

+0

Notado algo en la página ld man: --just-symbols = filename: "Lea los nombres de los símbolos y sus direcciones desde el nombre del archivo, pero no lo reubique ni lo incluya en la salida. Esto permite que su archivo de salida se refiera simbólicamente a ubicaciones absolutas de memoria definida en otros programas ". –

+0

Como la biblioteca compartida es un 'complemento' (es decir, no siempre está cargada), no puede proporcionar símbolos para otro código, especialmente la aplicación principal. Lo más fácil es convertir la biblioteca estática de terceros en una biblioteca dinámica. – KlaxSmashing

Cuestiones relacionadas