2009-04-03 3 views
9

Supposons que la bibliothèque A a() et b(). Si je lie mon programme B avec A et appelle un(), b() est-il inclus dans le binaire? Est-ce que le compilateur voit si une fonction quelconque dans l'appel de programme b() (peut-être un() appelle b() ou un autre lib appelle b())? Si oui, comment le compilateur obtient-il cette information? Si ce n'est pas le cas, n'est-ce pas un gros gâchis de la taille finale de la compilation si je suis en train de créer un lien vers une grande bibliothèque mais en n'utilisant qu'une fonctionnalité mineure?Comment les linkers décident-ils des parties des bibliothèques à inclure?

Répondre

0

Cela dépend de l'éditeur de liens, mais en général seules les fonctions réellement appelées sont incluses dans l'exécutable final. L'éditeur de liens fonctionne en recherchant le nom de la fonction dans la bibliothèque, puis en utilisant le code associé au nom.

Il y a très peu de livres sur les linkers, ce qui est étrange quand on pense à leur importance. Le texte pour un bon peut être trouvé here.

+0

-1 pour votre commentaire désagréable dans l'autre question. – Brian

0

Sans optimisation, oui, il sera inclus. Le lieur, cependant, pourrait être en mesure d'optimiser en analysant statiquement le code et en essayant de supprimer le code inaccessible.

9

Jetez un coup d'œil à link-time optimization. Ceci dépend nécessairement du fournisseur. Cela dépend aussi de la façon dont vous construisez vos binaires. Les compilateurs MS (à partir de 2005 au moins) fournissent quelque chose appelé Function Level Linking - qui est une autre façon de dépouiller les symboles dont vous n'avez pas besoin. This poste explique comment le même peut être atteint avec GCC (c'est vieux, GCC doit avoir évolué mais le contenu est pertinent à votre question).

Regardez également l'implémentation LLVM (et la section des exemples).

Je vous suggère également de jeter un oeil à Linkers and Loaders par John Levine - une excellente lecture.

+0

En général, l'optimisation de liaison concerne beaucoup plus que la suppression d'objets et de fonctions non référencés. LTO fait généralement référence à la technologie permettant d'optimiser le code généré au moment de la liaison. –

+0

@ Michael Burr: Correct. Mais c'est un endroit à rechercher. Aussi, c'est pourquoi j'ai cité tant de références. – dirkgently

+0

Bien sûr - Je ne voulais pas laisser entendre qu'il y avait quelque chose de mal avec la réponse - juste en soulignant que LTO est généralement beaucoup plus que la liaison au niveau de la fonction. –

1

Cela dépend de l'éditeur de liens.

par ex. Microsoft Visual C++ a une option "Activer le lien de niveau de fonction" afin que vous puissiez l'activer manuellement.

(je suppose qu'ils ont une raison de ne pas permettre que tout le temps ... peut-être plus lent liaison est ou quelque chose)

2

Habituellement les bibliothèques (statiques) sont composées d'objets créés à partir de fichiers source. Ce que font généralement les linkers, c'est inclure l'objet si une fonction fournie par cet objet est référencée. si votre fichier source contient seulement une fonction que seule cette fonction sera apportée par l'éditeur de liens. Il existe des linkers plus sophistiqués, mais la plupart des linkers basés sur C fonctionnent toujours comme indiqué. Il existe des outils disponibles qui divisent la source C contenant plusieurs fonctions en fichiers source artificiellement plus petits pour rendre la liaison statique plus fine.

Si vous utilisez des bibliothèques partagées, vous n'affectez pas la taille compilée en utilisant plus ou moins d'entre elles. Cependant, votre taille d'exécution les inclura.

0

Cela dépend des options transmises à l'éditeur de liens, mais généralement l'éditeur de liens supprimera les fichiers d'objet dans une bibliothèque qui ne sont référencés nulle part.

$ 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

Ce lecture à Academic Earth donne une vue d'ensemble assez bonne, la liaison est parlé près de la deuxième moitié de la conversation, IIRC.

8

Cela dépend.

Si la bibliothèque est un objet partagé ou une DLL, tout est chargé dans la bibliothèque, mais lors de l'exécution.Le coût en mémoire supplémentaire est (espérons-le) compensé par le partage de la bibliothèque (en fait, les pages de code) entre tous les processus en mémoire qui utilisent cette bibliothèque. C'est une grande victoire pour quelque chose comme libc .so, moins pour myreallyobscurelibrary.so. Mais vous ne posez probablement pas de questions sur les objets partagés, vraiment.

Les bibliothèques statiques sont simplement une collection de fichiers objets individuels, chacun étant le résultat d'une compilation (ou d'un assemblage) distincte, et éventuellement même pas écrit dans le même langage source. Chaque fichier objet possède un certain nombre de symboles exportés, et presque toujours un certain nombre de symboles importés.

Le travail de l'éditeur de liens consiste à créer un exécutable fini qui n'a plus aucun symbole importé indéfini. (Je ment, bien sûr, si la liaison dynamique est autorisée, mais supporte avec moi.) Pour ce faire, il commence par les modules nommés explicitement sur la ligne de commande de lien (et éventuellement implicitement dans sa configuration) et suppose que nommé explicitement doit faire partie de l'exécutable fini. Il tente ensuite de trouver des définitions pour tous les symboles non définis.

Habituellement, les modules d'objets nommés s'attendent à obtenir des symboles de certaines bibliothèques tels que libc.a.

Dans votre exemple, vous avez un seul module qui appelle la fonction a(), ce qui entraîne l'éditeur de liens recherchant le module qui exporte a().

Vous dîtes que la bibliothèque nommée A (sur unix, probablement libA.a) propose a() et b(), mais vous ne spécifiez pas comment. Vous avez laissé entendre que a() et b() ne s'appellent pas, ce que je suppose.

Si libA.a a été construit à partir a.o et b.o où chacun définit la fonction unique correspondante, puis l'éditeur de liens comprendra a.o et ignorer b.o.

Toutefois, si libA.a inclus ab.o qui définit à la fois a() et b() il comprendra ab.o dans le lien, la nécessité de satisfaire a(), et y compris la fonction inutilisée b().

Comme d'autres l'ont mentionné, il existe des linkers capables de séparer des fonctions individuelles des modules, et d'inclure uniquement celles qui sont réellement utilisées. Dans de nombreux cas, c'est une chose sûre à faire. Mais il est généralement plus sûr de supposer que votre éditeur de liens ne le fait pas, sauf si vous avez une documentation spécifique. Une autre chose à prendre en compte est que la plupart des linkers effectuent le moins de passages possible dans les fichiers et les bibliothèques nommés sur la ligne de commande, et construisent leur table de symboles au fur et à mesure. En pratique, cela signifie que c'est une bonne habitude de toujours spécifier les bibliothèques après tous les modules d'objet sur la ligne de commande de lien.

0

Cela dépend de l'éditeur de liens et de la manière dont la bibliothèque a été créée. Habituellement, les bibliothèques sont une combinaison de fichiers objets (les bibliothèques d'importation sont une exception majeure). Les liens plus anciens tireraient des choses dans l'image du fichier de sortie à une granularité des fichiers objets qui ont été placés dans la bibliothèque. Donc, si la fonction a() et la fonction b() étaient toutes les deux dans le même fichier objet, elles seraient toutes les deux dans le fichier de sortie - même si seulement une des 2 fonctions était réellement référencée.

C'est la raison pour laquelle vous verrez souvent des projets orientés bibliothèque avec une politique d'une seule fonction C par fichier source.De cette façon, chaque fonction est empaquetée dans son propre fichier objet et les linkers n'ont aucun problème à tirer uniquement sur ce qui est référencé. Notez toutefois que les nouveaux éditeurs de liens (en particulier les nouveaux liens Microsoft) ne peuvent extraire que des parties de fichiers objets référencés. Il est donc moins nécessaire aujourd'hui d'appliquer une stratégie de fichier à une fonction par source. - bien qu'il y ait des arguments raisonnables que cela devrait être fait de toute façon pour la maintenabilité.

Questions connexes