Je dois optimiser sévèrement la taille de mon exécutable (ARM
développement) et j'ai remarqué que dans mon schéma de construction actuel (gcc
+ ld
), les symboles non utilisés ne sont pas supprimés.
L'utilisation de la arm-strip --strip-unneeded
pour les exécutables/bibliothèques résultants ne change pas la taille de sortie de l’exécutable (je ne sais pas pourquoi, peut-être ne le peut-il tout simplement pas) .
Quel serait le moyen (s'il existe) de modifier mon pipeline de construction, afin que les symboles inutilisés soient supprimés du fichier résultant?
Je n’y penserais même pas, mais mon environnement embarqué actuel n’est pas très "puissant" et ne permet même pas la sauvegarde de 500K
hors de 2M
résulte en une très belle augmentation des performances de chargement.
Mise à jour:
Malheureusement, la version actuelle de gcc
que j’utilise n’a pas le -dead-strip
l'option et le -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, car j'étais sûr que gcc + ld
devrait automatiquement effacer les symboles inutilisés (pourquoi doivent-ils même les conserver?).
Pour GCC, cela se fait en deux étapes:
Commencez par compiler les données, puis dites au compilateur de séparer le code en sections distinctes au sein de l'unité de traduction. Cela sera fait pour les fonctions, les classes et les variables externes en utilisant les deux drapeaux suivants du compilateur:
-fdata-sections -ffunction-sections
Liez les unités de traduction en utilisant l'indicateur d'optimisation de l'éditeur de liens (pour que l'éditeur de liens supprime les sections non référencées):
-Wl,--gc-sections
Donc, si vous aviez un fichier appelé test.cpp contenant deux fonctions déclarées, mais que l’une d’elles était inutilisée, vous pouvez omettre le fichier inutilisé à l’aide de la commande suivante pour gcc (g ++):
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections
(Notez que -Os est un indicateur de compilation supplémentaire qui indique à GCC d’optimiser sa taille.)
Si ce fil est à croire, vous devez fournir le -ffunction-sections
et -fdata-sections
à gcc, ce qui placera chaque fonction et chaque objet dans sa propre section. Ensuite, vous donnez et --gc-sections
à GNU ld pour supprimer les sections inutilisées.
Vous voudrez vérifier votre documentation pour votre version de gcc & ld:
Cependant pour moi (OS X gcc 4.0.1) je les trouve pour ld
-dead_strip
Supprimez les fonctions et les données inaccessibles par le point d’entrée ou les symboles exportés.
-dead_strip_dylibs
Supprimez les fichiers inaccessibles par le point d'entrée ou les symboles exportés. En d’autres termes, supprime la génération de commandes de commande de chargement pour les dylibs qui n’ont fourni aucun symbole pendant la liaison. Cette option ne doit pas être utilisée lors de la liaison avec un dylib qui est requis au moment de l'exécution pour une raison indirecte telle que le dylib possède un important initialiseur.
Et cette option utile
-why_live symbol_name
Enregistre une chaîne de références à symbol_name. Applicable uniquement avec
-dead_strip
. Cela peut aider à comprendre pourquoi une chose que vous pensez devrait être supprimée n'est pas supprimée.
Il y a aussi une note dans l'homme de 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 être valables pour votre compilateur, je vous suggère de rechercher quelque chose de similaire dans vos documents.
Les habitudes de programmation pourraient aussi aider; par exemple. ajoutez static
aux fonctions qui ne sont pas accessibles en dehors d'un fichier spécifique; utilisez des noms plus courts pour les symboles (peut aider un peu, probablement pas trop); utilisation const char x[]
lorsque c'est possible; ... cet article , bien qu'il parle d'objets partagés dynamiques, peut contenir des suggestions qui, si elles sont suivies, peuvent vous aider à réduire la taille de votre sortie binaire finale (si votre cible est ELF).
La réponse est -flto
. Vous devez le transmettre à la fois à votre compilation et à votre lien, sinon il ne fait rien.
Cela fonctionne très bien - réduction de la taille d'un programme de microcontrôleur que j'ai écrit à moins de 50% de sa taille précédente!
Malheureusement, cela semblait un peu bogué - j'avais des exemples de choses qui n'étaient pas construites correctement. C’est peut-être dû au système de compilation que j’utilise (QBS; c’est une version très récente), mais dans tous les cas, je vous recommanderais de ne l’activer que pour votre compilation finale, si possible, et de tester soigneusement cette compilation.
Bien que la taille ne soit pas strictement liée aux symboles, compilez toujours avec -Os
et -s
drapeaux. -Os
optimise le code résultant pour une taille minimale d’exécutable et -s
supprime la table des symboles et les informations de déplacement de l'exécutable.
Parfois, si l'on souhaite une petite taille, jouer avec différents indicateurs d'optimisation peut avoir une signification ou non. 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 la bonne. Si ces instructions ne fonctionnent pas, le problème peut être lié à la version de gcc/ld que vous utilisez. À titre d'exercice, j'ai compilé un exemple de programme à l'aide d'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 ; }
Ensuite, j'ai compilé le code en utilisant des commutateurs de suppression de code mort 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 ont produit des exécutables de tailles respectives 8457, 8164 et 6160 octets, ce qui représente la contribution la plus importante provenant de la déclaration 'strip-all'. Si vous ne pouvez pas produire de réductions similaires sur votre plate-forme, votre version de gcc ne prend peut-être pas en charge 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 des symboles de votre exécutable. En réalité, il ne supprime aucun code exécutable.
Les bibliothèques standard obtiennent le résultat escompté en scindant toutes leurs fonctions dans des fichiers objet distincts, qui sont combinés à l'aide de ar
. Si vous liez ensuite l'archive résultante en tant que bibliothèque (c'est-à-dire, donnez l'option -l your_library
à ld) alors ld n'inclura que les fichiers objets, et donc les symboles, réellement utilisés.
Vous pouvez également trouver certaines des réponses à cette question similaire d'utilisation.
Je ne sais pas si cela vous aidera dans votre situation actuelle car il s'agit d'une fonctionnalité récente, mais vous pouvez spécifier la visibilité des symboles de manière globale. Qui passe -fvisibility=hidden -fvisibility-inlines-hidden
_ lors de la compilation peut aider l’éditeur de liens à 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.
De plus amples informations (et une approche fine pour les bibliothèques, par exemple) sont disponibles sur le wiki de GCC .
Extrait du manuel GCC 4.2.1, section -fwhole-program
:
Supposons que l'unité de compilation en cours représente l'ensemble du programme en cours de compilation. Toutes les fonctions et variables publiques à l'exception de
main
et de celles fusionnées par l'attributexternally_visible
deviennent des fonctions statiques et, dans un effet, sont optimisées de manière plus agressive par les optimiseurs interprocéduraux. Bien que cette option soit équivalente à une utilisation correcte du mot cléstatic
pour les programmes constitués d’un fichier unique, en combinaison avec l’option--combine
cet indicateur peut être utilisé pour compiler la plupart des programmes C à plus petite échelle car les fonctions et les variables deviennent locales pour l’ensemble de la compilation combinée, et non pour le fichier source unique lui-même.