web-dev-qa-db-fra.com

Pourquoi deux binaires de programmes avec seulement des commentaires modifiés ne correspondent-ils pas exactement dans gcc?

J'ai créé deux programmes C

  1. Programme 1

    int main()
    {
    }
    
  2. Programme 2

    int main()
    {
    //Some Harmless comments
    }
    

AFAIK, lors de la compilation, le compilateur (gcc) doit ignorer les commentaires et les espaces blancs redondants, et donc la sortie doit être similaire.

Mais quand j'ai vérifié les sommes md5 des binaires de sortie, elles ne correspondent pas. J'ai également essayé de compiler avec l'optimisation -O3 Et -Ofast Mais ils ne correspondaient toujours pas.

Que se passe-t-il ici?

EDIT: les commandes exactes et les sommes md5 sont (t1.c est le programme 1 et t2.c est le programme 2)

gcc ./t1.c -o aaa
gcc ./t2.c -o bbb
98c1a86e593fd0181383662e68bac22f  aaa
c10293cbe6031b13dc6244d01b4d2793  bbb

gcc ./t2.c -Ofast -o bbb
gcc ./t1.c -Ofast -o aaa
2f65a6d5bc9bf1351bdd6919a766fa10  aaa
c0bee139c47183ce62e10c3dbc13c614  bbb


gcc ./t1.c -O3 -o aaa
gcc ./t2.c -O3 -o bbb
564a39d982710b0070bb9349bfc0e2cd  aaa
ad89b15e73b26e32026fd0f1dc152cd2  bbb

Et oui, les sommes md5 correspondent sur plusieurs compilations avec les mêmes indicateurs.

BTW mon système est gcc (GCC) 5.2.0 et Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux

109
Registered User

C'est parce que les noms de fichiers sont différents (bien que la sortie des chaînes soit la même). Si vous essayez de modifier le fichier lui-même (plutôt que d'avoir deux fichiers), vous remarquerez que les binaires de sortie ne sont plus différents. Comme Jens et moi l'avons dit, c'est parce que GCC vide toute une charge de métadonnées dans les binaires qu'il construit, y compris le nom de fichier source exact (et AFAICS fait de même).

Essaye ça:

$ cp code.c code2.c subdir/code.c
$ gcc code.c -o a
$ gcc code2.c -o b
$ gcc subdir/code.c -o a2
$ diff a b
Binary files a and b differ
$ diff a2 b
Binary files a2 and b differ
$ diff -s a a2
Files a and a2 are identical

Cela explique pourquoi vos sommes md5 ne changent pas entre les builds, mais elles sont différentes entre les différents fichiers. Si vous le souhaitez, vous pouvez faire ce que Jens a suggéré et comparer la sortie de strings pour chaque binaire, vous remarquerez que les noms de fichiers sont incorporés dans le binaire. Si vous voulez "corriger" cela, vous pouvez strip les binaires et les métadonnées seront supprimés:

$ strip a a2 b
$ diff -s a b
Files a and b are identical
$ diff -s a2 b
Files a2 and b are identical
$ diff -s a a2
Files a and a2 are identical
158
cyphar

Les raisons les plus courantes sont les noms de fichiers et les horodatages ajoutés par le compilateur (généralement dans la partie info de débogage des sections ELF).

Essayez de courir

 $ strings -a program > x
 ...recompile program...
 $ strings -a program > y
 $ diff x y

et vous pourriez voir la raison. J'ai utilisé cela une fois pour trouver pourquoi la même source causerait un code différent lorsqu'elle est compilée dans différents répertoires. La conclusion a été que le __FILE__ macro développée en un nom de fichier absol, différent dans les deux arborescences.

27
Jens

Remarque : rappelez-vous que le nom du fichier source va dans le binaire non dépouillé, donc deux programmes provenant de fichiers sources nommés différemment auront des hachages différents.

Dans des situations similaires, si ce qui précède ne s'applique pas , vous pouvez essayer:

  • en exécutant strip contre le binaire pour éliminer la graisse. Si les binaires supprimés sont les mêmes, il s'agit de métadonnées qui ne sont pas essentielles au fonctionnement du programme.
  • générer une sortie intermédiaire d'assemblage pour vérifier que la différence ne se trouve pas dans les instructions CPU réelles (ou, cependant, pour mieux localiser où la différence est réellement est)
  • utilisez strings, ou videz les deux programmes en hexadécimal et exécutez un diff sur les deux vidages hexadécimaux. Une fois la ou les différences localisées, vous pouvez essayer de voir s'il y a des rimes ou des raisons (PID, horodatages, horodatage du fichier source ...). Par exemple, vous pourriez avoir une routine stockage de l'horodatage au moment de la compilation à des fins de diagnostic.
15
LSerni