Journal Compilation et optimisation de l'empreinte mémoire

Posté par  (site web personnel) .
Étiquettes : aucune
0
10
fév.
2005
Bonjour à tous,

l'année dernière, j'étais tombé un peu par hasard sur une page web très intéressante où un gars présentait comment obtenir un exécutable tout petit à partir d'un code C quelconque.

En gros, ça partait de la compilation simple d'un hello world (enfin, d'un équivalent légèrement plus complexe pour l'exemple), et l'auteur passait des options de compilation "-O" de gcc à strip, puis au link statique, puis au nettoyage des en-têtes du binaire ELF, jusqu'à l'optimisation proprement dite de l'assembleur, à la main :-)

Cette page était (est) très intéressante, d'autant plus qu'elle permettait de bien comprendre le mécanisme des binaires sous linux.
Et il se trouve que j'ai passé une bonne partie de l'après midi à la rechercher sur le net sans succès.. C'est pourquoi je me tourne vers vous pour savoir si quelqu'un n'aurait pas un exemple similaire, le plus complet possible... Voire, on peut toujours rêver, ladite page dans ses signets :-)
  • # Voila ?

    Posté par  . Évalué à 10.

    • [^] # Re: Voila ?

      Posté par  . Évalué à 3.

      Je vous recommande chaudement la lecture, le style est très agréable et super pédagogique.
      Et c'est vrai que le résultat est ... comment dire ... déconcertant.

      Nous avons à faire a un hacker, et un vrai de vrai.
    • [^] # Re: Voila ?

      Posté par  (site web personnel) . Évalué à 5.

      C'est EXACTEMENT cette page que je recherchais :-D
      Je ne sais comment te remercier... :-)
    • [^] # Re: Voila ?

      Posté par  . Évalué à 6.

      Oui, merci en effet !
      Dommage que le « plussage » soit plafonné à 10 points.

      Il est agréable de voir qu'il y a encore des gens qui se soucient de ce genre de chose à notre époque. D'ailleurs, à la mienne (il y a un peu plus de 10 ans :-) ), j'avais lancé le même genre de débat sur une messagerie Minitel à caractère informatique :

      Question : Quelle est la taille minimum d'un fichier exécutable (sous DOS) ?

      En utilisant un fichier *.COM, J'avais réussi à descendre à deux octets : CD 20
      Cela codait l'instruction "INT 20h", vieil appel système mais toujours implémenté à l'époque pour terminer une application avant que le célèbre B8 00 4C CD 21 (pour MOV ax,4c00h; int 21h ) n'implémente le code de retour.

      Je me suis quand même fait battre.

      Un connecté m'a fait remarquer qu'en utilisant simplement "RET" (1 octet), on provoquait un retour depuis la pile, qui pointait la fin de l'unique segment du programme, laquelle était par convention initialisée à 00 00. Or, tout au début du même segment (donc en 00 00) se trouvait le PSP, qui par norme commençait toujours par un magic number invariable : CD 20 (ce qui bien sûr n'était probablement pas un hasard) !

      Ensuite on s'est amusé à essayer de compiler un programme vide à l'aide de tous les compilateurs qui nous tombaient sous la main. La palme revenait au Turbo Pascal qui dépassait les 6Ko pour exécuter un programme strictement vide ! :-)

      C'était beaucoup lorsque l'on avait l'habitude de s'échanger les fichiers par disquette, que les graveurs de CD étaient extrêmement rares et que les disques durs n'atteignaient pas 1Go.
      • [^] # Re: Voila ?

        Posté par  . Évalué à 1.

        Je vois pas trop le rapport entre le plafond à 10 points pour le plussage d'un post et la qualité d'une page sur le web, mais tu dois avoir raison :)
      • [^] # Re: Voila ?

        Posté par  . Évalué à 3.

        La palme revenait au Turbo Pascal qui dépassait les 6Ko pour exécuter un programme strictement vide ! :-)


        Égalité avec Ada alors, je viens de faire le test et un programme "vide" (procedure principale avec "null" dedans) compilé avec gnatmake -O3, puis strippé, fait également 6KiO.
        • [^] # Re: Voila ?

          Posté par  . Évalué à 2.

          Oui, mais pas à la même époque, et pas non plus sur la même machine !

          Dans le même esprit, j'ai essayé hier soir sur mon PII/Mdk9.2 avec un gcc pas trop vieux le programme qu'il donne en exemple tout en haut de son exposé. Là où son exécutable commence à 8Ko, le mien atteint déjà 11Ko ! Après strip, en revanche, les tailles redeviennent comparables.

          Un programme vide de 6Ko il y a 10/12 ans, c'est un peu comme si le même programme vide aujourd'hui atteignait 100 à 300 Ko ! :-)
  • # Intéressant mais...

    Posté par  . Évalué à 1.

    Je n'ai pas encore lu l'article car le site est très lent à répondre.

    De plus en plus, la mémoire occupée par les programmes me semble démente. Mon navigateur montre rapidement à plus d'une centaine de Mo (d'après le gestionnaire des taches de windows), et même si la mesure de la mémoire occupée est sujet à diverses interprétation (comment compter les fichiers mappés qui sont en lecture seule, les librairies partagées entre différentes applications, les pages qui ne sont jamais utilisées) je pense qu'il y a des efforts à faire.

    Par contre, je suis très critique vis à vis des solutions citées:

    Pour le strip, pas de contestation.

    La compilation statique peut donner l'impression que le binaire est plus petit, mais on perd un gros intérêt des librairies dynamiques, qui est qu'il n'est plus nécessaire de les dupliquer en mémoire. Et puis le statique qui présente un intérêt pour un programme Hello World qui se contente d'appeler printf et exit est probablement un lourd handicape pour une application qui fait un peu plus de choses et qui va appeler bien plus de fonctions dans bien plus de librairies.

    Supprimer les parties ELF du binaire qui ne sont pas indispensable permet de faire gagner quelques octets, quelques Ko même peut-être, mais on se contente de gagner un peu de place sur le disque, cela ne change rien à la mémoire, et sur plusieurs dizaines ou quelques centaines de Mo, c'est complètement négligeable.

    Enfin l'optimisation en assembleur est à mon avis une régression au niveau des années 80. J'utilise à mi-temps un PPC, et évidement, l'assembleur concerne rarement cette architecture, une optimisation en assembleur pousse l'assertion Ordinateur = compatible IBM-PC qui masque une grande partie de la richesse de l'informatique, surtout libre.

    Optimiser une routine en assembleur peut se comprendre dans des situations où le temps est critique, pour utiliser des instructions mal supportées par le compilateur, elles ont leur place dans les librairies de codage/décodage audio et vidéo, et dans ce cas, il existe des alternatives portable pour les autres architectures; mais aucune écriture en assembleur ne va permettre de gagner une quantité significative de mémoire lors de l'exécution, le gain de quelques octets ne justifie pas la lourdeur , les problèmes de portabilité et de maintenance de l'assembleur, le C est suffisement souple de ce coté.
    • [^] # Re: Intéressant mais...

      Posté par  (site web personnel) . Évalué à 4.

      Attention a ne pas prendre cet article pour ce qu'il n'est pas. Ce n'est pas une méthodologie pour réduire la consommation de RAM de mozilla ou autre programme.

      C'est une expérience rigolote pour obtenir le binaire le plus petit possible sur un programme quasi-vide. Dans la conclusion, il dit qu'il a un binaire pour lequel chaque octet est utile et expliqué. Voila, c'est rigolo, c'est tout.
      • [^] # Re: Intéressant mais...

        Posté par  (site web personnel) . Évalué à 2.

        Euh, je ne dirais pas que c'est "juste rigolo". Il y a un réel esprit pédagogique derrière, quand même.
        L'exemple en lui même, c'est clair qu'il ne nous intéresse pas (qui voudrait d'un binaire qui ne fait que retourner 42 ?). Mais le voyage qui nous est offert est très riche en informations (comme tu le dis effectivement, il nous explique tout octet par octet), donc libre à toi d'en reprendre les infos qui t'intéressent dans le cadre de ton projet ou tes applications futures.

        Rigolo peut être, mais en tout cas très instructif, et complètement à l'inverse du concours du compilateur qui fournit le binaire le plus gros sur un code source qui ne fait rien (ÇA, c'est "rigolo, c'est tout" ) :-)
    • [^] # ...oui mais non :-)

      Posté par  (site web personnel) . Évalué à 1.

      Il y a beaucoup de vrai dans ce que tu dis, et d'ailleurs mon objectif n'est clairement pas de faire des binaires tout petits : sur un OS complet, ce serait une perte de temps ridicule que de chercher à optimiser entrifouillant l'assembleur à la main, binaire par binaire.

      En fait, je pense que beaucoup l'auront compris, l'idée est d'avoir une sorte de guide qui permette de mieux comprendre le mécanisme d'exécution d'un programme. Pour quelqu'un qui fait de l'embarqué et/ou de la compilation croisée, c'est un plus de bien saisir ces mécanismes. Et moi, je recherche justement une compréhension aussi complète que possible desdits mécanismes (notamment en ce qui concerne les librairies dynamiques).

      Et le site cité en premier commentaire est un excellent point de départ, explications reproductibles à l'appui. La théorie, je peux l'avoir sur n'importe quel autre site de même degré de sérieux; j'avais surtout besoin de la pratique pour mieux saisir ces mécanismes.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.