Outils pour utilisateurs

Outils du site


amelioration:taille:c

Cette page n'est utile que si la taille du programme est critique. À défaut, la simple option -Os est suffisante.

Collecter les informations

Map file

Ajouter l'option -Wl,-Map,binaire.map au LDFLAGS de la librairie ou de l'exécutable à générer.

Cela permet de récupérer la liste des symboles et la taille de toutes les fonctions que contiennent le binaire généré.

Binaire désassemblé

Modifier Makefile.am de la façon suivante :

all: all-am
  $(OBJDUMP) -h -S .libs/binaire.so > binaire.so.lss

objdump permet de désassembler un programme. Le code source sera aussi intégré si le code a été compilé avec des options de debug.

Cette méthode doit être utilisée et non gcc -S. L'objectif est d'analyser la taille de l'ensemble du projet et pas des fichiers objets indépendamment. Surtout que le lieur fait du gros ménage et se débarrasse de toutes les fonctions et symboles qui ne sont pas utilisés.

Fonctions pures virtuelles

Ces méthodes peuvent augmenter la taille du code avec l'ajout des méthodes

__cxa_pure_virtual
__stack_chk_fail

On peut remplacer facilement :

virtual void doIt() = 0;

par

virtual void doIt(){}

Méthode automatique

Options de GCC (Using the GNU Compiler Collection Archive) :

-ffunction-sections -fdata-sections même si la documentation semble dire l'inverse.

g++ -ffunction-sections -fdata-sections -c -o example.o example.cpp

When you specify these options, the assembler and linker create larger object and executable files and are also slower.

-fno-enforce-eh-specs

Don’t generate code to check for violation of exception specifications at run time. This option violates the C++ standard, but may be useful for reducing code size in production builds, much like defining NDEBUG. This does not give user code permission to throw exceptions in violation of the exception specifications; the compiler still optimizes based on the specifications, so throwing an unexpected exception results in undefined behavior at run time.

Option pour le lieur : -Wl,--gc-sections (GNAT User’s Guide for Native Platforms, Archive)

g++ -Wl,--gc-sections example_cpp example.o

Supprimer toutes références à malloc (ou autre)

Tout d'abord s'assurer que ni malloc ni free n'est utilisé mais également aucun new ni delete.

Ensuite, il convient de “surcharger” la fonction C weak __register_exitproc. Il s'agit d'une fonction exécutée au démarrage du programme qui est nécessaire pour que l'application s'arrête correctement. Le problème est que cette fonction fait appel à la fonction malloc. De plus, un microcontrôleur n'a pas besoin de s'arrêter proprement, il est censé tourner 24 heures sur 24. Si cette fonction n'est pas définie, gcc ajoute donc la sienne. Il suffit donc de la définir quelque part dans le code.

#if defined (__cplusplus)
extern "C" {
#endif
int
__register_exitproc(int type, void (*fn) (void), void *arg, void *d)
{
  return -1;
}
#if defined (__cplusplus)
}
#endif

Ensuite, en regardant le fichier .map du programme compilé, il est constaté la présence d'une variable __malloc_av_ avec un espace mémoire de taille 0x408 (1032 octets). L'objectif va donc être de récupérer cet espace mémoire.

Il est indiqué qu'elle est définie dans libc.a(lib_a-mallocr.o)

Faire une sauvegarde du fichier libc.a d'origine puis exécuter les commandes suivantes dans un dossier vide après avoir copier la librairie statique concernée :

ar -x libc.a
del lib_a-mallocr.o lib_a-freer.o lib_a-malloc.o libc.a
ar r libc.a *.o

Tous les fichiers objets supprimés précédemment l'ont été par itération. Par exemple freer dépend de mallocr.

Renouveler l'opération suivante avec le fichier libstdc++.a :

ar -x libstdc++.a
del del_op.o "libstdc++.a"
ar r "libstdc++.a" *.o

Cependant, avec la programmation orientée objet, le compilateur va mal vivre le fait de ne plus avoir de destructeur.

Il est alors nécessaire de déclarer l'opérateur delete, en c++ uniquement.

void operator delete(void *)
{
}

Et alors, la variable __malloc_av_ aura alors disparu comme par magie. Mais il faut bien noter que le compilateur ne sera plus en mesure d'effectuer de malloc/new ni de free/delete. Il s'agit donc d'une modification à faire dans un environnement contrôlé.

Après avoir détecté l'origine de la dépendant et réussi à compiler sans les objets précédemment supprimés, il est maintenant possible de remettre en place les librairies statiques (libc.a et libcstdc++.a) d'origine et normalement, la dépendance ne devrait pas réapparaitre.

amelioration/taille/c.txt · Dernière modification : 2017/09/10 12:35 de root