Forum Programmation.c GCC et taille des exécutables

Posté par  .
Étiquettes : aucune
0
26
jan.
2008
Bonsoir,
je viens de me rendre compte que le programme suivant:
fichier: minimal.c
int main(){ return 0;}

génère un exécutable de 6,2ko lorsqu'on le compile avec GCC de la façon suivante:
gcc minimal.c -o minimal
Pourtant normalement (sous linux) le code assembleur de ce programme est le suivant:
.global _start
_start: mov $1,%eax /* Mettre 1 dans eax (appel système ''Exit'') */
mov $0,%ebx /* Mettre 0 dans ebx (valeur de retour du programme) */
int $0x80 /* Interruption 0x80, executant un appel systeme sous Linux) */

Et ce code assembleur une fois assemblé fait 460 octets.

J'ai l'impression qu'il y a une question de runtime C derrière tout ça, mais j'avoue que j'ai quand même un peu de mal à comprendre comment GCC réussit à inclure plus de 6ko de données inutiles: il n'y a pas de suppression du code mort dans GCC?

Merci pour vos lumières!
  • # 460 octets pour ça ?!?

    Posté par  . Évalué à 5.

    deux mov et un int ? je crois que tu te fais rouler :)

    bon, il faut un poil plus d'enrobage pour que ca tourne mais au final tu peux t'en tirer en 45 octets.

    http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm(...)
    • [^] # Re: 460 octets pour ça ?!?

      Posté par  . Évalué à 1.

      surement 460octets avec les commentaires

      sinon pour son code qui fait 6.2Ko
      il faut surement ajouté les "entetes" qui decrivent le fichier comme etant binaire, eventuellement (enfin j'imagine) le mapping memoire necessaire à ce programme

      Gniarf : je viens de lire ton lien, tres instructif.
  • # Readelf, objdump

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

    Deux choses importantes.

    La première, c'est que ton code C est fonctionnellement équivalent au code assembleur, mais ce n'est pas pour ça qu'ils sont identiques. main() et _start, c'est pas pareil. Dans le cas du code en C, la fonction main() est appelée par la libc (c'est elle qui définit le _start). Donc, par défaut, ton programme en C est lié dynamiquement à la libc. Ça prend un peu de place.

    Ensuite, le plus gourmand en taille : gcc, par défaut, n'est pas avare d'informations.
    Utilise readelf -a minimal ou objdump -x minimal pour lister tout ce qui se trouve dans ton exécutable. Toutes les sections présentes dans ton ELF sont facultative et ne servent qu'à donner des informations (par exemple pour déboguer, mais pas seulement).

    En bref, ce n'est pas du tout du "code mort". Ce sont des informations complètement facultatives, mais qui peuvent être très utiles.

    Le programme sstrip, des Elf-Kickers, permet d'enlever un bon paquet de ces infos facultatives.
    • [^] # Re: Readelf, objdump

      Posté par  . Évalué à 1.

      ton code C est fonctionnellement équivalent au code assembleur, mais ce n'est pas pour ça qu'ils sont identiques. main() et _start, c'est pas pareil

      C'est justement ça le problème: GCC devrait utiliser la méthode la plus efficace en temps et en taille, non?
      Toutes les sections présentes dans ton ELF sont facultatives et ne servent qu'à donner des informations (par exemple pour déboguer, mais pas seulement

      Voilà ce que j'ai essayé:
      gilles@ordi:~$ strip --strip-all --remove-section=".comment" minimal -o minimal_stripped
      gilles@ordi:~$ strip --strip-all --remove-section=".comment" cminimal -o cminimal_stripped
      gilles@ordi:~$ ls -l cminimal minimal cminimal_stripped minimal_stripped
      -rwxr-xr-x 1 gilles gilles 6332 2008-01-26 22:31 cminimal
      -rwxr-xr-x 1 gilles gilles 2556 2008-01-26 22:37 cminimal_stripped
      -rwxr-xr-x 1 gilles gilles 596 2008-01-26 22:12 minimal
      -rwxr-xr-x 1 gilles gilles 248 2008-01-26 22:37 minimal_stripped

      Apparement, la commande strip permet la suppression de code mort dans le cas du programme C mais aussi dans le cas du programme ASM.
      Donc au final, en utilisant strip, on a toujours un facteur 10 entre les tailles des exécutables.

      PS: Au boulot j'utilise des DSP motorola qui ont 16Ko de mémoire programme, et on arrive quand même à faire pas mal de choses (en assembleur), donc je trouve que prendre 6ko pour un programme en C qui ne fait rien c'est abusé.
      • [^] # Re: Readelf, objdump

        Posté par  (site Web personnel) . Évalué à 6.

        GCC devrait utiliser la méthode la plus efficace en temps et en taille, non?


        Tu peux commencer par regarder du coté de l'option -nostdlib
        À toi alors d'ajuster ton code C comme il faut pour que ça fonctionne toujours. Le fonctionnement standard du C, c'est que la libc est disponible.

        strip permet la suppression de code mort


        Non, ce n'est pas du "code mort". À moins que tu n'appelles "code" la section .comments ?

        Le reste, ce sont des informations, parfois nécessaire à l'OS :
        - Quel est l'interpréteur ? (/lib/ld-linux.so.2 ou /lib64/ld-linux-x86-64.so.2)
        - Quelles sont les bibliothèques nécessaires pour faire tourner le programme ? (la libc)
        - Quelles versions nécessaires desdites bibliothèques ? (parfois, il y a un changement d'ABI entre les versions)
        - Quels sont les symboles qui sont visibles de l'extérieur ? (le main, pour qu'il puisse être appelé)
        - Quels sont les symboles externes qui sont visibles dans le programme ? (stdin, stdout, optarg, ... par défaut, libc oblige)
        - Comment doit être configurée la pile ? (non-exécutable)

        un facteur 10

        Dans ce cas extrême où le programme ne fait rien. Je passe, la comparaison est spécieuse.

        ... [DSP Motorola] ... [6ko pour un programme en C qui ne fait rien] ...

        Ton programme C fait en réalité beaucoup de choses pour que l'OS puisse l'utiliser de manière optimale (ou même parfois l'utiliser tout court). Le programme du DSP a beaucoup moins de contraintes à ce niveau.
        • [^] # Re: Readelf, objdump

          Posté par  . Évalué à 1.

          Merci pour ta réponse, je comprends mieux à présent. Effectivement, en ouvrant les fichiers binaires avec un éditeur hexadécimal, je me suis rendu compte qu'il y a pas mal de chaînes de caractères qui contiennent des noms "manglés".

          Par ailleurs le lien donné par Gniarf m'a fait découvrir l'option -nostdlib de GCC, et ça m'a aussi permis de découvrir que:
          * GCC fait *toujours* le lien avec la libc.
          * la fonction main est une fonction fournie par la libc, pas par le langage.

          Merci pour ces explications!
  • # relire...

    Posté par  . Évalué à 1.

    A mon avis, qui n'engage evidemment que moi...


    PS: Au boulot j'utilise des DSP motorola qui ont 16Ko de mémoire programme, et on arrive quand même à faire pas mal de choses (en assembleur), donc je trouve que prendre 6ko pour un programme en C qui ne fait rien c'est abusé.


    relis bien les 2 posts precedents et le lien fournit plus haut.
    entre ecrire un programme en assembleur sans commentaire et sans lien/description
    et ecrire un programme en C qui sort un format executable.
    il y a des differences.

    d'ailleurs le lien donné par le premier post explique bien cela.
    meme ton code assembleur, une fois "compilé" prend plus que place que le code en lui meme

    alors que dans le DSP tu lui envoie uniquement le code assembleur et pas le code compilé...
    • [^] # Re: relire...

      Posté par  . Évalué à 1.

      le DSP tu lui envoie uniquement le code assembleur et pas le code compilé

      Non, le DSP tu lui envoies le code assemblé qui peut prendre effectivement plus de place que le code lui-même.
  • # C'est une blague ?

    Posté par  . Évalué à 4.

    Non, sérieux, cette discussion, c'est une blague ? Je voyais déjà exactement ce même type de discussion il y a 14 ans. Et quand je dis exactement, c'est du mot pour mot, et un étonnement, une naïveté identiques.

    Faut avancer les enfants, si les linkages par défaut de GCC ne vous conviennent pas, vous faites les votre, qui feront moins de choses, mais qui seront plus petit.
    • [^] # Re: C'est une blague ?

      Posté par  . Évalué à 9.

      Je voyais déjà exactement ce même type de discussion il y a 14 ans. Et quand je dis exactement, c'est du mot pour mot, et un étonnement, une naïveté identiques.

      Heureux de l'apprendre.
      Il y a 14 ans j'avais 12 ans, j'espère que tu ne m'en veux pas de ne pas avoir suivi les discussions de l'époque.
      • [^] # Re: C'est une blague ?

        Posté par  . Évalué à 2.

        Il t'en veut peut-être juste de ne pas avoir cherché un peu avant de poser la question.

Suivre le flux des commentaires

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