128 votes

Comment supprimer les symboles C/C++ inutilisé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 schéma de construction actuel ( gcc + ld ) les symboles inutilisé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 qu'il ne peut tout simplement pas). .

Quelle serait la façon (s'il existe) de modifier mon pipeline de construction, de sorte 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 l'économie d'énergie, même si elle n'est pas très importante, n'en est qu'à ses débuts. l'économie même 500K de 2M se traduit par un gain de performances de chargement très appréciable.

Mise à jour :

Malheureusement, l'actuel gcc que j'utilise n'a pas l'option -dead-strip et l'option -ffunction-sections... + --gc-sections pour ld ne donne pas de différence significative pour la sortie résultante.

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

0 votes

Comment savez-vous que les symboles ne sont pas utilisés ?

2 votes

N'est référencé nulle part => n'est pas utilisé dans l'application finale. Je suppose que la construction du graphe d'appel pendant le couplage/la liaison ne devrait pas être très difficile.

1 votes

Essayez-vous de réduire la taille du fichier .o en supprimant les morts ? symboles ou vous essayez de réduire la taille de l'empreinte réelle du code une fois chargé dans la mémoire exécutable ? Le fait que vous disiez "embarqué" laisse entendre la seconde hypothèse ; la question que vous posez semble axée sur la première.

146voto

J T Points 2333

Pour GCC, cela se fait en deux étapes :

Commencez par compiler les données, mais 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 de compilation suivants :

-fdata-sections -ffunction-sections

Lier les unités de traduction ensemble en utilisant l'indicateur d'optimisation de l'éditeur de liens (cela permet à l'éditeur de liens de rejeter les sections non référencées) :

-Wl,--gc-sections

Ainsi, si vous avez un fichier appelé test.cpp dans lequel deux fonctions sont déclarées, mais que l'une d'entre elles est inutilisée, vous pouvez omettre la fonction inutilisée en envoyant 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 compilation additionnel qui indique à GCC d'optimiser pour la taille)

4 votes

Veuillez noter que cela ralentira l'exécutable selon la description des options de GCC (j'ai testé).

1 votes

Avec mingw cela ne fonctionne pas lorsque l'on lie statiquement libstdc++ et libgcc avec l'indicateur -static . L'option de l'éditeur de liens -strip-all aide un peu, mais l'exécutable (ou la dll) généré est toujours 4 fois plus gros que ce que Visual Studio aurait généré. Le fait est que je n'ai aucun contrôle sur la façon dont libstdc++ a été compilé. Il devrait y avoir un ld seule option.

37voto

Nemo Points 32838

Si ce fil est à croire, vous devez fournir l'information suivante -ffunction-sections y -fdata-sections à gcc, qui mettra chaque fonction et objet de données dans sa propre section. Ensuite, vous donnez et --gc-sections à GNU ld pour supprimer les sections inutilisées.

0 votes

Malheureusement, cela n'a pas fonctionné, je n'ai aucune idée pourquoi, probablement la arm-gcc problème de compilateur ou autre ARM -... en rapport. S'il y a autre chose que je peux essayer...

0 votes

@Michael : C'est vrai, mais les liens de documentation que j'ai fournis sont actuels et semblent soutenir l'idée que cela devrait fonctionner... Oh bien.

0 votes

C'est toujours valable. Je n'ai jamais compris pourquoi ce n'est pas la valeur par défaut de GCC ; je me demande même si la valeur par défaut actuelle (conserver les symboles inutilisés) a un sens.

27voto

Michael Anderson Points 21181

Vous devez vérifier votre documentation pour votre version de gcc et ld :

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

-dead_strip

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

-dead_strip_dylibs

Supprime les dylibs qui sont inaccessibles par le point d'entrée ou les symboles exportés. C'est-à-dire, supprime la génération de commandes de chargement pour les dylibs qui n'ont fourni aucun symbole pendant la liaison. Cette option ne devrait pas être utilisée lors de la liaison avec une dylib qui est requise à l'exécution pour une raison indirecte telle que la dylib a un initialisateur important.

Et cette option utile

-why_live symbol_name

Enregistre une chaîne de références à symbol_name. Seulement applicable avec -dead_strip . Il peut aider à déboguer la raison pour laquelle quelque chose que vous pensez être une bande morte supprimée ne l'est pas.

Il y a également une note dans le manuel gcc/g++ indiquant 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 votre documentation.

0 votes

Cela ne semble rien faire avec mingw .

0 votes

-dead_strip n'est pas un gcc option.

0 votes

-dead_strip est transmis par gcc à l'éditeur de liens, mais n'est supporté que sur Darwin (macOS).

23voto

ShinTakezou Points 5603

Les habitudes de programmation pourraient également être utiles ; par exemple, ajoutez les éléments suivants static aux fonctions auxquelles on n'accède pas 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[] dans la mesure du possible ; ... cet article 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).

4 votes

En quoi est-il utile de choisir des noms plus courts pour les symboles ?

1 votes

Si les symboles ne sont pas dépouillés, ça va sans dire-mais il semble que cela devait être dit maintenant.

0 votes

@fuz L'article parle d'objets partagés dynamiques (ex. .so sur Linux), les noms des symboles doivent donc être conservés pour que des API comme celle de Python ctypes Le module FFI peut les utiliser pour rechercher les symboles par leur nom au moment de l'exécution.

13voto

zxcdw Points 1218

Bien que cela ne concerne pas strictement les symboles, si vous recherchez la taille, compilez toujours avec -Os y -s drapeaux. -Os optimise le code résultant pour une taille minimale de l'exécutable, et -s supprime la table de symboles et les informations de relocalisation de l'exécutable.

Parfois, si une petite taille est souhaitée, jouer avec différents drapeaux d'optimisation peut avoir - ou non - une signification. Par exemple, le fait de basculer -ffast-math et/ou -fomit-frame-pointer peut parfois vous faire économiser des dizaines d'octets.

0 votes

La plupart des ajustements d'optimisation donneront toujours un code correct tant que vous vous conformerez à la norme du langage, mais j'ai eu -ffast-math fait des ravages dans un code C++ totalement conforme aux normes, je ne le recommanderais donc jamais.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X