Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente |
amelioration:taille:c [2017/06/30 20:32] – ↷ Page déplacée et renommée de amelioration:taille à amelioration:taille:c root | amelioration:taille:c [2017/09/10 12:35] (Version actuelle) – déplacement pdf root |
---|
=====Comment réduire la taille d'un programme===== | |
| |
Cette page n'est utile que si la taille du programme est critique. À défaut, la simple option ''-Os'' est suffisante. | Cette page n'est utile que si la taille du programme est critique. À défaut, la simple option ''-Os'' est suffisante. |
| |
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. | 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. |
| |
=====TODO===== | ====Fonctions pures virtuelles==== |
| Ces méthodes peuvent augmenter la taille du code avec l'ajout des méthodes |
| __cxa_pure_virtual |
| __stack_chk_fail |
| |
Comment supprimer toutes références à malloc dans les micro-controleurs. | On peut remplacer facilement : |
| virtual void doIt() = 0; |
| par |
| virtual void doIt(){} |
| |
Tout d'abord s'assurer que ni malloc ni free n'est utilisé mais également aucun new ni delete. | =====Méthode automatique===== |
| Options de GCC ([[https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc.pdf|Using the GNU Compiler Collection]] {{ :prog:gcc:gcc-7.2.0.pdf |Archive}}) : |
| |
Ensuite, il convient de "surcharger" la fonction C __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 microcontroleur n'a pas besoin de s'arrêter proprement, il est censé tourner 24 heures sur 24. | ''-ffunction-sections -fdata-sections'' même si la documentation semble dire l'inverse. |
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. | g++ -ffunction-sections -fdata-sections -c -o example.o example.cpp |
| <blockquote> When you specify these options, the assembler and linker create larger object and executable files and are also slower.</blockquote> |
| |
| ''-fno-enforce-eh-specs'' |
| |
| <blockquote>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.</blockquote> |
| |
| Option pour le lieur : ''-Wl,%%--%%gc-sections'' ([[https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gnat_ugn.pdf|GNAT User’s Guide for Native Platforms]], {{ :prog:gnat:gnat_ugn-7.2.0.pdf |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. |
| |
| <code c> |
#if defined (__cplusplus) | #if defined (__cplusplus) |
extern "C" { | extern "C" { |
} | } |
#endif | #endif |
| </code> |
| |
| 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. |
| |
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)'' |
Il est indiqué qu'elle est définie dans libc.a(lib_a-mallocr.o) | |
| |
Faire 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 : | 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 | ar -x libc.a |
del lib_a-mallocr.o lib_a-freer.o lib_a-malloc.o libc.a | del lib_a-mallocr.o lib_a-freer.o lib_a-malloc.o libc.a |
ar r libc.a *.o | ar r libc.a *.o |
Tous les fichiers objets supprimés précédemment l'on été par itération. Par exemple freer dépend de mallocr. | 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 : | Renouveler l'opération suivante avec le fichier ''libstdc++.a'' : |
ar -x libstdc++.a | ar -x libstdc++.a |
del del_op.o "libstdc++.a" | del del_op.o "libstdc++.a" |
ar r "libstdc++.a" *.o | 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. | 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. | Il est alors nécessaire de déclarer l'opérateur delete, en c++ uniquement. |
| |
| <code c> |
void operator delete(void *) | void operator delete(void *) |
{ | { |
} | } |
| </code> |
| |
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. | 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é. | Il s'agit donc d'une modification à faire dans un environnement contrôlé. |
| |
Après avoir détecté l'origine de la dépendant, il est maintenant possible de remettre en place les librairies static (libc.a et libcstdc++.a) d'origine et normalement, la dépendance ne devrait pas réapparaitre. | 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. |