2009-04-03 7 views
9

Supongamos que la biblioteca A tiene a() y b(). Si enlace mi programa B con A y llamo a a(), ¿se incluye b() en el binario? ¿El compilador ve si alguna función en la llamada al programa b() (quizás a() llama a b() u otra lib llama a b())? Si es así, ¿cómo obtiene el compilador esta información? Si no, ¿no es esto una gran pérdida de tamaño de compilación final si me estoy conectando a una gran biblioteca pero solo usando una función menor?¿Cómo deciden los vinculadores qué partes de las bibliotecas incluir?

Respuesta

0

Depende del vinculador, pero en general solo las funciones que realmente se llaman se incluyen en el ejecutable final. El enlazador funciona buscando el nombre de la función en la biblioteca y luego usando el código asociado con el nombre.

Hay muy pocos libros sobre vinculadores, lo que es extraño cuando se piensa en lo importantes que son. El texto para uno bueno se puede encontrar here.

+0

-1 para su desagradable comentario en la otra pregunta. – Brian

0

Sin ninguna optimización, sí, se incluirá. El vinculador, sin embargo, podría optimizar al analizar estáticamente el código e intentar eliminar el código inalcanzable.

9

Eche un vistazo a link-time optimization. Esto es necesariamente dependiente del vendedor. También dependerá de cómo construyas tus binarios. Los compiladores de MS (al menos en adelante 2005) proporcionan algo llamado Function Level Linking, que es otra forma de eliminar símbolos que no necesita. La publicación This explica cómo se puede lograr lo mismo con GCC (esto es antiguo, GCC debe haberse movido pero el contenido es relevante para su pregunta).

También eche un vistazo a la implementación LLVM (y la sección de ejemplos).

Sugiero que también eche un vistazo a Linkers and Loaders por John Levine - una excelente lectura.

+0

Generalmente, la optimización de tiempo de enlace aborda mucho más que eliminar objetos y funciones sin referencia (LTO generalmente se refiere a la tecnología que puede optimizar el código generado en tiempo de enlace), como funciones de delimitación o reconociendo que los punteros no son objetos de aliasing. –

+0

@Michael Burr: Correcto. Pero ese es un lugar para buscar. Además, esta es la razón por la que cité tantas referencias. – dirkgently

+0

Claro, no quise dar a entender que haya algo de malo en la respuesta, simplemente señalé que LTO generalmente es mucho más que vincular el nivel de función. –

1

Depende del vinculador.

por ejemplo. Microsoft Visual C++ tiene una opción "Habilitar vinculación de nivel de función" para que pueda habilitarla manualmente.

(I asumen que tienen una razón para no sólo permite que todo el tiempo ... tal vinculación es más lenta o algo así)

2

Por lo general, las bibliotecas (estáticos) se componen de objetos creados a partir de archivos de origen. Lo que los enlazadores suelen hacer es incluir el objeto si se hace referencia a una función proporcionada por ese objeto. si su archivo fuente solo contiene una función, el enlazador solo la traerá. Hay enlaces más sofisticados, pero la mayoría de los vinculadores basados ​​en C todavía funcionan como se indica. Hay herramientas disponibles que dividen fuente C que contienen múltiples funciones en archivos fuente artificialmente más pequeños para hacer enlaces estáticos más finos granulares.

Si está utilizando bibliotecas compartidas, entonces no afecta su tamaño compilado usando más o menos de ellas. Sin embargo, su tamaño de tiempo de ejecución los incluirá.

0

Depende de las opciones que se pasen al enlazador, pero normalmente el enlazador dejará de lado los archivos de objeto en una biblioteca que no están referenciados en ninguna parte.

$ cat foo.c 
int main(){} 

$ gcc -static foo.c 

$ size 
    text data  bss  dec  hex filename 
452659 1928 6880 461467 70a9b a.out 

# force linking of libz.a even though it isn't used 
$ gcc -static foo.c -Wl,-whole-archive -lz -Wl,-no-whole-archive 

$ size 
    text data  bss  dec  hex filename 
517951 2180 6844 526975 80a7f a.out 
1

Este lecture al Academic Earth da una buena visión general, la vinculación se habla de cerca de la mitad posterior de la charla, IIRC.

8

Depende.

Si la biblioteca es un objeto compartido o una DLL, todo en la biblioteca se carga, pero en tiempo de ejecución.El costo en memoria extra se compensa (con suerte) al compartir la biblioteca (en realidad, las páginas de códigos) entre todos los procesos en la memoria que usan esa biblioteca. Esta es una gran ganancia para algo como libc .so, menos para myreallyobscurelibrary.so. Pero probablemente no estés preguntando sobre objetos compartidos, realmente.

Las bibliotecas estáticas son simplemente una colección de archivos de objetos individuales, cada uno como resultado de una compilación (o conjunto) separada, y posiblemente ni siquiera están escritos en el mismo idioma de origen. Cada archivo de objeto tiene una serie de símbolos exportados, y casi siempre una cantidad de símbolos importados.

El trabajo del enlazador es crear un ejecutable terminado que no tenga símbolos importados indefinidos restantes. (Estoy mintiendo, por supuesto, si está permitido el enlace dinámico, pero tengan paciencia conmigo). Para hacerlo, comienza con los módulos nombrados explícitamente en la línea de comando del enlace (y posiblemente implícitamente en su configuración) y asume que cualquier módulo nombrado explícitamente debe ser parte del ejecutable terminado. Luego intenta encontrar definiciones para todos los símbolos indefinidos.

Normalmente, los módulos de objeto con nombre esperan obtener símbolos de alguna biblioteca, como libc.a.

En su ejemplo, tiene un único módulo que llama a la función a(), que dará como resultado que el vinculador busque el módulo que exporta a().

Usted dice que la biblioteca llamada A (en Unix, probablemente libA.a) ofrece a() y b(), pero no especifica cómo. Usted dio a entender que a() y b() no se llaman entre ellos, lo que supondré.

Si libA.a fue construido a partir a.o y b.o donde cada uno define la función única correspondiente, a continuación, el enlazador incluirá a.o e ignorar b.o.

Sin embargo, si libA.a incluido ab.o que define tanto a() y b() entonces se incluirán ab.o en el enlace, que satisface la necesidad de a(), e incluyendo la función no utilizada b().

Como han mencionado otros, hay enlazadores que son capaces de dividir funciones individuales de módulos e incluir solo aquellos que realmente se usan. En muchos casos, eso es algo seguro de hacer. Pero generalmente es más seguro suponer que su enlazador no hace eso a menos que tenga documentación específica.

Otra cosa a tener en cuenta es que la mayoría de los enlazadores hacen el menor número posible de pases a través de los archivos y bibliotecas nombrados en la línea de comandos y construyen su tabla de símbolos a medida que avanzan. Como cuestión práctica, esto significa que es una buena práctica especificar siempre las bibliotecas después de todos los módulos de objeto en la línea de comando del enlace.

0

Depende del vinculador y de cómo se creó la biblioteca. Por lo general, las bibliotecas son una combinación de archivos de objetos (las bibliotecas de importación son una gran excepción a esto). Los enlazadores más antiguos extraían cosas en la imagen del archivo de salida en una granularidad de los archivos objeto que se colocaron en la biblioteca. Entonces, si la función a() y la función b() estuvieran ambas en el mismo archivo de objeto, ambas estarían en el archivo de salida, incluso si solo se hace referencia a una de las 2 funciones.

Esta es una razón por la que a menudo verá proyectos orientados a bibliotecas con una política de una sola función C por archivo de origen.De esta forma, cada función se empaqueta en su propio archivo de objeto y los vinculadores no tienen problemas para extraer solo lo que se referencia.

Sin embargo, tenga en cuenta que los enlazadores más nuevos (sin duda los más nuevos) pueden extraer solo partes de los archivos objeto a los que se hace referencia, por lo que no es necesario aplicar una política de archivo de una función por fuente. - aunque hay argumentos razonables de que eso debe hacerse de todos modos para la mantenibilidad.

Cuestiones relacionadas