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

J’ai besoin d’optimiser la taille de mon exécutable (développement ARM ) 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 arm-ssortingp --ssortingp-unneeded pour les exécutables / bibliothèques résultants ne modifie pas la taille de sortie de l’exécutable (je ne sais pas pourquoi, peut-être que c’est impossible) .

Quelle serait la manière (si elle existe) de modifier mon pipeline de construction, de sorte que les symboles non utilisés soient supprimés du fichier résultant?


Je ne penserais même pas à cela, mais mon environnement embarqué actuel n’est pas très “puissant” et économiser même 500K sur 2M traduit par une très bonne augmentation des performances de chargement.

Mettre à jour:

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

Je suis choqué que cela devienne même un problème, car j’étais sûr que gcc + ld devrait automatiquement supprimer les symboles non utilisés (pourquoi doivent-ils même les conserver?).

    Pour GCC, cela se fait en deux étapes:

    Comstackz d’abord les données mais demandez au compilateur de séparer le code en sections distinctes dans l’unité de traduction. Cela sera fait pour les fonctions, les classes et les variables externes en utilisant les deux indicateurs de compilation suivants:

     -fdata-sections -ffunction-sections 

    Reliez les unités de traduction à l’aide de l’indicateur d’optimisation de l’éditeur de liens (cela entraîne la suppression par l’éditeur de liens des sections non référencées):

     -Wl,--gc-sections 

    Donc, si vous aviez un fichier appelé test.cpp qui contenait deux fonctions déclarées, mais que l’une d’elles n’était pas utilisée, vous pourriez omettre l’inutilisé avec la commande suivante dans gcc (g ++):

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

    (Notez que -Os est un indicateur de compilateur supplémentaire qui indique à GCC d’optimiser la taille)

    Si l’on en croit ce thread , vous devez fournir les -ffunction-sections et -fdata-sections à gcc, qui placera chaque fonction et object de données dans sa propre section. Ensuite, vous donnez et --gc-sections à GNU ld pour supprimer les sections inutilisées.

    Vous voudrez vérifier vos documents pour votre version de gcc & ld:

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

     -dead_ssortingp 

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

     -dead_ssortingp_dylibs 

    Supprimez les dylibs inaccessibles au point d’entrée ou aux symboles exportés. Cela supprime la génération de commandes de chargement pour les dylibs qui ne fournissaient aucun symbole pendant le lien. Cette option ne doit pas être utilisée lors de la liaison avec un dylib requirejs à l’exécution pour une raison indirecte telle que le dylib a un initialiseur important.

    Et cette option utile

     -why_live symbol_name 

    Enregistre une chaîne de références à symbol_name. Seulement applicable avec -dead_ssortingp . Cela peut aider à déboguer la raison pour laquelle quelque chose qui, selon vous, devrait être enlevé par une bande morte, n’est pas supprimé.

    Il y a également une note dans le gcc / g ++ man que certains types d’élimination du 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 documents.

    Les habitudes de programmation pourraient aussi aider; par exemple, append static fonctions 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); utilisez const char x[] dans la mesure du possible; … cet article , bien qu’il parle d’objects partagés dynamics, peut contenir des suggestions qui, si elles sont suivies, peuvent aider à réduire la taille finale de votre sortie binary (si votre cible est ELF).

    La réponse est -flto . Vous devez le transmettre à la fois à votre compilation et à vos étapes de lien, sinon cela ne fait rien.

    Cela fonctionne vraiment très bien – réduit 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 cas où les choses n’étaient pas construites correctement. Cela est 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 que si possible, et de tester cette version.

    Il me semble que la réponse fournie par Nemo est la bonne. Si ces instructions ne fonctionnent pas, le problème est peut-être lié à la version de gcc / ld que vous utilisez. En guise d’exercice, j’ai compilé un exemple de programme en utilisant les instructions détaillées ici.

     #include  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 progressivement 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,--ssortingp-all 

    Ces parameters de compilation et de liaison ont produit respectivement des exécutables de taille 8457, 8164 et 6160 octets, la consortingbution la plus importante provenant de la déclaration «ssortingp-all». Si vous ne pouvez pas produire des réductions similaires sur votre plate-forme, alors peut-être que votre version de gcc ne prend pas en charge cette fonctionnalité. J’utilise gcc (4.5.2-8ubuntu4), ld (2.21.0.20110327) sous Linux Mint 2.6.38-8-generic x86_64

    Bien que ce ne soit pas ssortingctement une question de symboles, si vous -Os pour la taille, comstackz toujours avec les -Os et -s . -Os optimise le code résultant pour la taille minimale de l’exécutable et -s supprime la table des symboles et les informations de relocalisation de l’exécutable.

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

    ssortingp --ssortingp-unneeded ne fonctionne que sur la table des symboles de votre exécutable. Il ne supprime en fait aucun code exécutable.

    Les bibliothèques standard obtiennent le résultat que vous recherchez en divisant toutes leurs fonctions en fichiers objects séparés, 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 inclura uniquement les fichiers objects, et donc les symboles, qui sont réellement utilisés.

    Vous pouvez également trouver certaines des réponses à cette question d’utilisation similaire .

    Je ne sais pas si cela aidera avec 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. Passer -fvisibility=hidden -fvisibility-inlines-hidden à la compilation peut aider l’éditeur de liens à se débarrasser ultérieurement 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 les bibliothèques par exemple) sont disponibles sur le wiki GCC .

    A partir du manuel GCC 4.2.1, section -fwhole-program :

    Supposons que l’unité de compilation actuelle représente un programme entier en cours de compilation. Toutes les fonctions et variables publiques à l’exception de main et de celles fusionnées par l’atsortingbut externally_visible deviennent des fonctions statiques et sont optimisées de manière plus agressive par les optimiseurs interprocéduraux. Bien que cette option soit équivalente à l’utilisation correcte du mot-clé static pour les programmes constitués d’un seul fichier, en combinaison avec l’option --combine cet indicateur peut être utilisé pour comstackr la plupart des programmes C à petite échelle. unité, pas pour le fichier source unique lui-même.

    Vous pouvez utiliser un fichier binary sur un fichier object (par exemple, un exécutable) pour en supprimer tous les symboles.

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