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?).
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)
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.
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.
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).
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.
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.
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
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.
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 .
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'attributexternally_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.
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.