Comment supprimer les symboles C/C++ non utilisés avec GCC et ld?

j'ai besoin d'optimiser la taille de mon exécutable sévèrement ( ARM développement) et J'ai remarqué que dans mon programme de construction actuel ( gcc + ld ) les symboles inutilisés ne sont pas dépouillés.

L'utilisation du arm-strip --strip-unneeded pour les exécutables / bibliothèques résultants ne change pas la taille de sortie de l'exécutable (Je n'ai aucune idée pourquoi, peut-être il ne peut tout simplement pas) .

quel serait le chemin (s'il existe) pour modifier mon pipeline de construction, de sorte que les symboles inutilisés soient retirés du fichier résultant?


Je n'y penserais même pas, mais mon environnement intégré actuel n'est pas très "puissant" et économiser même 500K sur 2M se traduit par une très belle augmentation des performances de chargement.

mise à jour:

malheureusement le la version actuelle gcc que j'utilise n'a pas l'option -dead-strip et la -ffunction-sections... + --gc-sections pour ld ne donne aucune différence significative pour la sortie résultante.

je suis choqué que cela soit même devenu un problème, parce que j'étais sûr que gcc + ld devrait automatiquement enlever les symboles inutilisés (pourquoi doivent-ils même les garder?).

93

11 réponses

pour GCC, ceci est accompli en deux étapes:

compilez D'abord les données mais dites au compilateur de séparer le code en sections séparées au sein de l'Unité de traduction. Cela sera fait pour les fonctions, les classes et les variables externes en utilisant les deux options de compilateur suivantes:

-fdata-sections -ffunction-sections

relier les unités de traduction ensemble en utilisant le drapeau d'optimisation de l'éditeur de liens (ce qui amène l'éditeur de liens à rejeter les sections non référencées):

-Wl,--gc-sections

donc si vous aviez un fichier appelé test.cpp qui avait deux fonctions déclarées, mais dont l'une n'était pas utilisée, Vous pouvez omettre celle non utilisée avec la commande suivante à gcc (g++):

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections

(notez que-Os est un drapeau de compilateur supplémentaire qui dit à GCC d'optimiser pour la taille)

105
répondu J T 2015-04-11 10:02:53

si ce fil doit être cru, vous devez fournir le -ffunction-sections et -fdata-sections à gcc, qui mettra chaque fonction et objet de données dans sa propre section. Puis vous donnez et --gc-sections à GNU ld pour supprimer les sections inutilisées.

31
répondu Nemo 2017-06-22 23:35:29

vous voulez vérifier votre docs pour votre version de gcc & ld:

Cependant pour moi (OS X gcc 4.0.1) je les trouve pour ld

-dead_strip

supprimer les fonctions et les données inaccessibles par le point d'entrée ou les symboles exportés.

-dead_strip_dylibs

supprimer les dylibes inaccessibles par le point d'entrée ou les symboles exportés. C'est-à-dire, supprime la génération de commandes de charge pour les dylibs qui n'a fourni aucun symbole pendant le lien. Cette option ne doit pas être utilisée lors de la liaison contre un dylib qui est requis à l'exécution pour une raison indirecte telle que le dylib a un initialiseur important.

et cette option utile

-why_live symbol_name

Logs une chaîne de références à symbol_name. Uniquement applicable avec -dead_strip . Il peut aider à déboguer pourquoi quelque chose que vous pensez devrait être la bande morte enlevé n'est pas retiré.

il y a aussi une note dans l'homme gcc/g++ que certains types d'élimination de code mort ne sont effectués que si l'optimisation est activée lors de la compilation.

bien que ces options/conditions puissent ne pas tenir pour votre compilateur, je vous suggère de chercher quelque chose de similaire dans vos docs.

22
répondu Michael Anderson 2011-07-16 03:11:03

les habitudes de programmation pourraient aussi aider; par exemple, ajouter static à des fonctions qui ne sont pas accessibles en dehors d'un fichier spécifique; utiliser des noms plus courts pour les symboles (peut aider un peu, probablement pas trop); utiliser const char x[] si possible; ... ce papier , bien qu'il parle d'objets partagés dynamiques, peut contenir des suggestions qui, si elles sont suivies, peuvent aider à réduire la taille de votre sortie binaire finale (si votre cible est ELF).

19
répondu ShinTakezou 2011-07-16 14:26:51

la réponse est -flto . Vous devez passer à votre compilation et de liaison des étapes, sinon il ne fait rien.

Il fonctionne très bien réduite à la taille d'un microcontrôleur programme que j'ai écrit à moins de 50% de sa taille!

malheureusement, il semblait un peu buggé - j'ai eu des cas de choses n'étant pas construit correctement. Cela peut être dû au système de construction que j'utilise (QBS; c'est très nouveau), mais dans tous les cas Je vous recommande de ne l'activer pour votre construction finale que si possible, et de tester cette construction à fond.

14
répondu Timmmm 2014-07-18 10:29:48

bien qu'il ne s'agisse pas uniquement de symboles, Si vous optez pour la taille, compilez toujours avec les drapeaux -Os et -s . -Os optimise le code résultant pour la taille minimale de l'exécutable et -s supprime la table de symboles et les informations de déplacement de l'exécutable.

parfois-si une petite taille est souhaitée - jouer avec différents indicateurs d'optimisation peut - ou ne pas - avoir une signification. Par exemple basculer -ffast-math et / ou -fomit-frame-pointer peut parfois vous sauver même des dizaines d'octets.

12
répondu zxcdw 2012-06-22 12:23:52

Il me semble que la réponse fournie par Nemo est le bon. Si ces instructions ne fonctionnent pas, la question peut être liée à la version de gcc / ld que vous utilisez, comme un exercice j'ai compilé un programme d'exemple en utilisant des instructions détaillées ici

#include <stdio.h>
void deadcode() { printf("This is d dead codez\n"); }
int main(void) { printf("This is main\n"); return 0 ; }

puis j'ai compilé le code en utilisant des commutateurs de suppression de code morts de plus en plus agressifs:

gcc -Os test.c -o test.elf
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-all

ces paramètres de compilation et de liaison produit des exécutables de taille 8457, 8164 et 6160 octets, respectivement, la contribution la plus importante provenant de la déclaration "strip-all". Si vous ne pouvez pas produire des réductions similaires sur votre plate-forme,alors peut-être que votre version de gcc ne supporte pas cette fonctionnalité. J'utilise gcc (4.5.2-8ubuntu4), ld (2.21.0.20110327) sur Linux Mint 2.6.38-8-generic x86_64

11
répondu Gearoid Murphy 2011-07-18 13:44:32

strip --strip-unneeded ne fonctionne que sur la table de symboles de votre exécutable. Il ne fait pas de supprimer tout le code de l'exécutable.

les bibliothèques standards atteignent le résultat que vous recherchez en divisant toutes leurs fonctions en fichiers d'objets séparés, qui sont combinés en utilisant ar . Si vous liez alors l'archive résultante comme une bibliothèque (C.-à-d. donnez l'option -l your_library à ld) alors ld n'inclura que les fichiers d'objets, et donc les symboles, qui sont en fait utiliser.

, Vous pouvez également trouver quelques éléments de réponse à cette la même question d'utilisation.

7
répondu Andrew Edgecombe 2017-05-23 11:55:03

Je ne sais pas si cela vous aidera dans votre situation difficile actuelle car il s'agit d'une fonctionnalité récente, mais vous pouvez spécifier la visibilité des symboles d'une manière globale. Passer -fvisibility=hidden -fvisibility-inlines-hidden à la compilation peut aider le linker à se débarrasser plus tard des symboles inutiles. Si vous produisez un exécutable (par opposition à une bibliothèque partagée), il n'y a plus rien à faire.

plus d'informations (et une approche fine pour par exemple les bibliothèques) est disponible sur le wiki GCC .

4
répondu Luc Danton 2011-07-17 16:01:30

du manuel GCC 4.2.1, section -fwhole-program :

supposons que l'Unité de compilation actuelle représente l'ensemble du programme en cours de compilation. Toutes les fonctions publiques et les variables à l'exception de main et celles fusionnées par l'attribut externally_visible deviennent des fonctions statiques et dans un affect devient plus agressivement optimisé par des optimiseurs interprocedural. Alors que cette option est équivalente à l'utilisation correcte du mot-clé static pour les programmes composé d'un seul fichier, en combinaison avec l'option --combine ce drapeau peut être utilisé pour compiler la plupart des programmes C à petite échelle puisque les fonctions et les variables deviennent locales pour l'ensemble de l'Unité de compilation combinée, pas pour le fichier source unique lui-même.

4
répondu awiebe 2017-08-13 12:50:54

vous pouvez utiliser le strip binaire sur le dossier d'objet(par exemple. exécutable) pour supprimer tous les symboles.

Note: il modifie le fichier lui-même et ne crée pas de copie.

-1
répondu ton4eg 2015-11-24 18:43:09