2008-12-26 18 views
20

Estoy buscando formas de restringir el número de símbolos C exportados a una biblioteca estática de Linux (archivo). Me gustaría limitar estos a solo aquellos símbolos que son parte de la API oficial de la biblioteca. Ya uso 'estático' para declarar la mayoría de las funciones como estáticas, pero esto las restringe al alcance del archivo. Estoy buscando una forma de restringir el alcance a la biblioteca.Restricción de símbolos en una biblioteca estática de Linux

Puedo hacer esto para bibliotecas compartidas usando las técnicas en How to Write Shared Libraries de Ulrich Drepper, pero no puedo aplicar estas técnicas a archivos estáticos. En su anterior Good Practices in Library Design papel, escribe:

La única posibilidad es combinar todos los archivos de objetos que necesitan ciertos recursos internos en una usando -r 'ld' y luego restringir los símbolos que son exportados por esto combinado archivo de objeto. El enlazador GNU tiene opciones para hacer solo esto.

¿Alguien podría ayudarme a descubrir cuáles podrían ser estas opciones? He tenido cierto éxito con 'strip -w -K prefix_ *', pero esto se siente brutal. Idealmente, me gustaría una solución que funcione tanto con GCC 3 como con 4.

¡Gracias!

Respuesta

0

Mi forma de hacerlo es marcar todo lo que no se va a exportar con INTERNAL, incluir guardar todos los archivos .h, compilar compilaciones de desarrollo con -DINTERNAL = y compilar compilaciones de lanzamiento con un solo archivo .c que incluya todo otros archivos .c de biblioteca con -DINTERNAL = static.

+0

Funcionaría si tiene todo en un archivo o puede compilarlo. A menudo no lo haces. A veces necesitas tener pequeños archivos para combinar con otros idiomas (por ejemplo, Haskell, esa es la razón por la que encontré esta página). –

+0

@Maciej: Bien OP preguntó acerca de gcc ... – Joshua

10

Las bibliotecas estáticas no pueden hacer lo que usted quiere para el código compilado con GCC 3.xo 4.x.

Si puede usar objetos compartidos (bibliotecas), el enlazador GNU hace lo que necesita con una característica llamada script de versión. Esto generalmente se usa para proporcionar puntos de entrada específicos de la versión, pero el caso degenerado solo distingue entre símbolos públicos y privados sin ningún control de versiones. Se especifica un script de versión con la opción de línea de comando --version-script = para ld.

El contenido de una secuencia de comandos versión que hace que la entrada señala foo y bar público y oculta todas las otras interfaces:

{ global: foo; bar; local: *; }; 

ver el documento en ld: http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION

Soy un gran defensor de la bibliotecas compartidas, y esta capacidad de limitar la visibilidad de los globales es una de sus grandes virtudes.

Un documento que proporciona más de las ventajas de los objetos compartidos, pero escrito para Solaris (por Greg Nakhimovsky de feliz memoria), es por lo http://developers.sun.com/solaris/articles/linker_mapfiles.html

espero que esto ayude.

9

No creo que GNU ld tenga tales opciones; Ulrich debe haber querido decir objcopy, que tiene muchas de estas opciones: --localize-hidden, --localize-symbol=symbolname, --localize-symbols=filename.

El --localize-hidden en particular permite que uno tenga un control muy fino sobre qué símbolos están expuestos.Considere:

int foo() { return 42; } 
int __attribute__((visibility("hidden"))) bar() { return 24; } 

gcc -c foo.c 
nm foo.o 
000000000000000b T bar 
0000000000000000 T foo 

objcopy --localize-hidden foo.o bar.o 
nm bar.o 
000000000000000b t bar 
0000000000000000 T foo 

Así bar() ya no se exporta desde el objeto (a pesar de que todavía está presente y utilizable para la depuración). También puede eliminar bar() todo junto con objcopy --strip-unneeded.

+0

Un problema que veo con esto, es que tienes que hacerlo en todos los archivos de objeto. Otro problema es el caso del OP, cuando desea tener funciones internas en una biblioteca estática distribuida en varios archivos de objetos, si "oculta" un símbolo en un archivo objeto, ¿cómo se puede acceder desde otro archivo objeto en el archivo objeto? misma biblioteca estática? –

+0

Gracias. No tenía idea de que existía objcopy y me solucionó un gran dolor de cabeza. –

6

Los méritos de esta respuesta dependerán de por qué está utilizando bibliotecas estáticas. Si es para permitir que el enlazador deje caer objetos no utilizados más tarde, entonces tengo poco que agregar. Si es por motivos de organización, lo que minimiza el número de objetos que se deben pasar para vincular aplicaciones, esta extensión de la respuesta del ruso empleado puede ser útil.

En tiempo de compilación, la visibilidad de todos los símbolos dentro de una unidad de compilación se puede ajustar usando:

-fvisibility=hidden 
-fvisibility=default 

Esto implica que uno puede compilar un solo archivo "interface.c" con visibilidad predeterminada y un mayor número de archivos de implementación con visibilidad oculta, sin anotar la fuente. Un enlace reubicable producirá entonces un solo archivo de objeto donde las funciones no API se "oculta":

ld -r interface.o implementation0.o implementation1.o -o relocatable.o 

El archivo objeto combinado ahora se puede someter a objcopy:

objcopy --localize-hidden relocatable.o mylibrary.o 

Así tenemos una archivo de objeto único "biblioteca" o "módulo" que expone solo la API deseada.


La estrategia anterior interactúa moderadamente bien con la optimización del tiempo de enlace. Compilar con -flto y realizar el enlace reubicable pasando -r al enlazador a través del compilador:

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o 

Uso objcopy para localizar los símbolos ocultos como antes, a continuación, llamar el enlazador un tiempo final para despojar los símbolos locales y cualquier otro código muerto que pueda encontrar en el objeto post-lto. Lamentablemente, es poco probable que relocatable.o han conservado ninguna información relacionada lto:

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o 

Las implementaciones actuales de LTO parecen estar activo durante la etapa de enlace reubicable. Con lto on, los símbolos ocultos => locales fueron eliminados por el enlace reubicable final. Sin lto, los símbolos ocultos => locales sobrevivieron al último enlace reubicable.

Las futuras implementaciones de lto parecen guardar los metadatos requeridos a través de la etapa de enlace reubicable, pero en este momento el resultado del enlace reubicable parece ser un archivo de objeto viejo simple.

Cuestiones relacionadas