26 votes

La compilation d'un programme deux fois produit-elle un binaire identique bit à bit ?

Si je devais compiler un programme en un seul binaire, faire une somme de contrôle, puis le recompiler sur la même machine avec le même compilateur et les mêmes paramètres de compilation et faire une somme de contrôle du programme recompilé, la somme de contrôle échouerait-elle ?

Si oui, pourquoi ? Si ce n'est pas le cas, le fait d'avoir une unité centrale différente donnerait-il lieu à un binaire non identique ?

8 votes

Cela dépend du compilateur. Certains d'entre eux intègrent des horodateurs, la réponse est donc "non" pour ceux-là.

0 votes

En fait, cela dépend de la format exécutable et non le compilateur. Certains formats d'exécutables, comme le format PE de Windows, incluent un horodatage qui est lié à l'heure et à la date de compilation, tandis que d'autres formats, comme le format ELF de Linux, ne le font pas. Quoi qu'il en soit, cette question dépend de la définition de "binaire identique". L'image elle-même sera/devrait être identique sur le plan binaire si le même fichier source est compilé avec le même compilateur, les mêmes bibliothèques, les mêmes commutateurs et tout le reste, mais l'en-tête et les autres métadonnées peuvent varier.

19voto

rici Points 3733
  1. Compilez le même programme avec les mêmes paramètres sur la même machine :

    Bien que la réponse définitive soit "cela dépend", il est raisonnable de s'attendre à ce que la plupart des compilateurs soient déterministes la plupart du temps, et que les binaires produits soient identiques. En effet, certains systèmes de contrôle de version en dépendent. Néanmoins, il y a toujours des exceptions ; il est tout à fait possible que un peu de Le compilateur décidera quelque part d'insérer un horodatage ou autre (il me semble que Delphi le fait, par exemple). Ou bien le processus de compilation lui-même peut le faire ; j'ai vu des makefiles pour des programmes C qui fixent une macro de préprocesseur à l'horodatage actuel. (Je suppose que cela compterait comme étant un paramètre différent du compilateur, cependant).

    De plus, soyez conscient que si vous liez statiquement le binaire, vous incorporez effectivement l'état de toutes les bibliothèques pertinentes sur votre machine, et tout changement dans l'une d'entre elles affectera également votre binaire. Les paramètres du compilateur ne sont donc pas les seuls à être pertinents.

  2. Compiler le même programme sur une autre machine avec une autre unité centrale.

    Ici, tous les paris sont ouverts. La plupart des compilateurs modernes sont capables d'effectuer des optimisations spécifiques à la cible ; si cette option est activée, alors les binaires sont susceptibles de différer à moins que les CPUs soient similaires (et même dans ce cas, c'est possible). Voir également la note ci-dessus sur l'édition de liens statiques : l'environnement de configuration va bien au-delà des paramètres du compilateur. À moins que vous n'ayez un contrôle très strict de la configuration, il est extrêmement probable que quelque chose diffère entre les deux machines.

9voto

  • -frandom-seed=123 contrôle le caractère aléatoire interne de GCC. man gcc dit :

    Cette option fournit une graine que GCC utilise à la place de nombres aléatoires pour générer certains noms de symboles qui doivent être différents dans chaque fichier compilé. Elle est également utilisée pour placer des timbres uniques dans les fichiers de données de couverture et les fichiers objets qui les produisent. Vous pouvez utiliser l'option -frandom-seed pour produire des fichiers d'objets identiques de manière reproductible.

  • __FILE__ : mettre la source dans un dossier fixe (ex. /tmp/build )

  • pour __DATE__ , __TIME__ , __TIMESTAMP__ :

    • libfaketime : https://github.com/wolfcw/libfaketime
    • remplacer ces macros par -D
    • -Wdate-time o -Werror=date-time : avertir ou échouer si __TIME__ , __DATE__ o __TIMESTAMP__ sont utilisés. Le noyau Linux 4.4 l'utilise par défaut.
  • utiliser le D drapeau avec ar ou utiliser https://github.com/nh2/ar-timestamp-wiper/tree/master pour essuyer les timbres

  • -fno-guess-branch-probability : anciennes versions du manuel dire que c'est une source de non-déterminisme, mais plus maintenant . Je ne suis pas sûr que cela soit couvert par -frandom-seed ou pas.

Le projet Debian Projet de constructions reproductibles tentent de standardiser les paquets Debian octet par octet, et ont récemment obtenu un Bourse de la Fondation Linux . Cela ne se limite pas à la compilation, mais cela devrait vous intéresser.

Buildroot a un BR2_REPRODUCIBLE qui peut donner quelques idées au niveau du paquet, mais elle est loin d'être complète à ce stade.

Fils connexes :

8voto

halivingston Points 385

Ce que vous demandez est "est-ce que la sortie déterministe ." Si vous compilez le programme une fois et le recompilez immédiatement, vous obtiendrez probablement le même fichier de sortie. Cependant, si quelque chose changeait - même un petit changement - en particulier dans un composant que le programme compilé utilise, alors la sortie du compilateur pourrait aussi changer.

7voto

Paul Smith Points 339

La recompilation d'un programme produit-elle un binaire identique bit à bit ?

Pour tous les compilateurs ? Non. Le compilateur C#, au moins, n'est pas autorisé à le faire.

Eric Lippert a un exposé très complet sur les raisons pour lesquelles la sortie du compilateur n'est pas déterministe .

[Par conception, le compilateur C# ne produit jamais deux fois le même binaire. Le compilateur C# incorpore un GUID fraîchement généré dans chaque assemblage, à chaque fois que vous l'exécutez, garantissant ainsi que deux assemblages ne sont jamais identiques bit à bit. Pour citer la spécification du CLI :

La colonne Mvid doit indexer un GUID unique [...] qui identifie cette instance du module. [Le Mvid doit être généré à nouveau pour chaque module [...] Bien que le [runtime] lui-même n'utilise pas le Mvid, d'autres outils (comme les débogueurs [...]) s'appuient sur le fait que le Mvid diffère presque toujours d'un module à l'autre.

Bien qu'il soit spécifique à une version du compilateur C#, de nombreux points de l'article peuvent être appliqués à l'ensemble de l'Europe. tout compilateur.

Tout d'abord, nous supposons que nous obtenons toujours la même liste de fichiers à chaque fois, dans le même ordre. Mais dans certains cas, cela dépend du système d'exploitation. Lorsque vous dites "csc *.cs", l'ordre dans lequel le système d'exploitation propose la liste des fichiers correspondants est un détail d'implémentation du système d'exploitation ; le compilateur ne trie pas cette liste dans un ordre canonique.

3voto

cherouvim Points 18550

Je dirais que NON, ce n'est pas déterministe à 100%. J'ai déjà travaillé avec une version de GCC qui génère des binaires cibles pour le processeur Hitachi H8.

Ce n'est pas un problème d'horodatage. Même si le problème de l'horodatage est ignoré, l'architecture spécifique du processeur peut permettre à la même instruction d'être codée de 2 manières légèrement différentes où certains bits peuvent être 1 ou 0. Mon expérience précédente montre que les binaires générés étaient les mêmes LA PLUPART du temps mais occasionnellement, gcc générait des binaires de taille identique mais dont certains octets étaient différents de seulement 1 bit, par exemple 0XE0 devient 0XE1.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X