Warum stimmen zwei Binärdateien von Programmen mit nur geänderten Kommentaren nicht genau in gcc überein?
Lesezeit: 6 Minuten
registrierter Nutzer
Ich habe zwei C-Programme erstellt
Programm 1
int main()
{
}
Programm 2
int main()
{
//Some Harmless comments
}
AFAIK, beim Kompilieren sollte der Compiler (gcc) die Kommentare und redundanten Whitespaces ignorieren, und daher muss die Ausgabe ähnlich sein.
Aber als ich die MD5-Summen der Ausgabebinärdateien überprüft habe, stimmen sie nicht überein. Ich habe auch versucht, mit Optimierung zu kompilieren -O3 und -Ofast aber sie passten immer noch nicht zusammen.
Was passiert hier?
BEARBEITEN: die genauen Befehle und dort md5sums sind (t1.c ist Programm 1 und t2.c ist Programm 2)
Und ja, md5sums stimmen über mehrere Kompilationen mit denselben Flags überein.
BTW mein System ist gcc (GCC) 5.2.0 und Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux
Bitte geben Sie Ihre genauen Befehlszeilen-Flags an. Sind zum Beispiel Debug-Informationen überhaupt in den Binärdateien enthalten? Wenn ja, würde sich die Änderung der Zeilennummern offensichtlich darauf auswirken …
– Jon Skeet
4. September 2015 um 14:51 Uhr
Ist die MD5-Summe über mehrere Builds desselben Codes konsistent?
– wenig begeisterter Benutzer
4. September 2015 um 14:51 Uhr
Ich kann das nicht reproduzieren. Ich hätte vermutet, dass dies daran liegt, dass der GCC beim Kompilieren eine ganze Reihe von Metadaten in Binärdateien einbettet (einschließlich Zeitstempel). Wenn Sie das hinzufügen könnten präzise Befehlszeilen-Flags, die Sie verwendet haben, das wird nützlich sein.
– Cyphar
4. September 2015 um 14:53 Uhr
Anstatt nur MD5-Summen zu überprüfen und hängen zu bleiben, hexdump und diff, um genau zu sehen, welche Bytes sich unterscheiden
– MM
5. September 2015 um 10:39 Uhr
Obwohl die Antwort auf die Frage “Was ist der Unterschied zwischen den beiden Compilerausgaben?” Interessant ist, stelle ich fest, dass die Frage eine ungerechtfertigte Annahme hat: dass die beiden Ausgänge sollte gleich sein und dass wir welche benötigen Erläuterung warum sie anders sind. Alles, was der Compiler Ihnen verspricht, ist, dass, wenn Sie ihm ein legales C-Programm geben, die Ausgabe eine legale ausführbare Datei ist, die dieses Programm implementiert. Dass zwei beliebige Ausführungen des Compilers dieselbe Binärdatei erzeugen, ist keine Garantie des C-Standards.
– Eric Lippert
5. September 2015 um 18:47 Uhr
Cyphar
Das liegt daran, dass die Dateinamen unterschiedlich sind (obwohl die Ausgabe der Zeichenfolgen dieselbe ist). Wenn Sie versuchen, die Datei selbst zu ändern (anstatt zwei Dateien zu haben), werden Sie feststellen, dass die ausgegebenen Binärdateien nicht mehr unterschiedlich sind. Wie sowohl Jens als auch ich sagten, liegt es daran, dass GCC eine ganze Menge Metadaten in die von ihm erstellten Binärdateien ablegt, einschließlich des genauen Quelldateinamens (und AFAICS tut das auch).
Versuche dies:
$ 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
Dies erklärt, warum sich Ihre MD5-Summen zwischen Builds nicht ändern, aber zwischen verschiedenen Dateien unterschiedlich sind. Wenn Sie möchten, können Sie tun, was Jens vorgeschlagen hat, und die Ausgabe von vergleichen strings Für jede Binärdatei werden Sie feststellen, dass die Dateinamen in die Binärdatei eingebettet sind. Wenn Sie dies “reparieren” möchten, können Sie dies tun strip Die Binärdateien und die Metadaten werden entfernt:
$ 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
BEARBEITEN: Aktualisiert, um zu sagen, dass Sie die Binärdateien entfernen können, um das Problem zu “beheben”.
– Cyphar
4. September 2015 um 15:21 Uhr
Und deshalb sollten Sie die Assembly-Ausgabe vergleichen, nicht MD5-Prüfsummen.
– Leichtigkeitsrennen im Orbit
4. September 2015 um 18:06 Uhr
Ich habe hier eine Anschlussfrage gestellt.
– Federico Poloni
5. September 2015 um 13:27 Uhr
Je nach Objektdateiformat wird auch die Kompilierzeit in den Objektdateien gespeichert. Die Verwendung von COFF-Dateien zum Beispiel wäre also nicht identisch mit den Dateien a und a2.
– Martin Rosenau
6. September 2015 um 9:41 Uhr
Jens
Der häufigste Grund sind Dateinamen und Zeitstempel, die vom Compiler hinzugefügt wurden (normalerweise im Debug-Info-Teil der ELF-Abschnitte).
Versuchen Sie es mit Laufen
$ strings -a program > x
...recompile program...
$ strings -a program > y
$ diff x y
und Sie könnten den Grund sehen. Ich habe dies einmal verwendet, um herauszufinden, warum dieselbe Quelle unterschiedlichen Code verursachen würde, wenn sie in verschiedenen Verzeichnissen kompiliert wird. Die Feststellung war, dass die __FILE__ Makro erweitert zu einem absolut Dateiname, in beiden Bäumen unterschiedlich.
Entsprechend gcc.gnu.org/ml/gcc-help/2007-05/msg00138.html (veraltet, ich weiß) sie speichern keine Zeitstempel und es könnte ein Linker-Problem sein. Ich erinnere mich jedoch, dass ich kürzlich eine Geschichte darüber gelesen habe, wie eine Sicherheitsfirma die Arbeitsgewohnheiten eines Hackerteams mithilfe der GCC-Zeitstempelinformationen in ihren Binärdateien profiliert hat.
– Cyphar
4. September 2015 um 15:01 Uhr
Und ganz zu schweigen davon, dass OP angibt, dass “md5sums über mehrere Kompilierungen mit denselben Flags übereinstimmen”, was darauf hinweist, dass es wahrscheinlich nicht die Zeitstempel sind, die das Problem verursachen. Dies liegt wahrscheinlich daran, dass es sich um unterschiedliche Dateinamen handelt.
– Cyphar
4. September 2015 um 15:04 Uhr
@cyphar Unterschiedliche Dateinamen sollten auch vom strings/diff-Ansatz erfasst werden.
– Jens
4. September 2015 um 15:16 Uhr
LSerni
Notiz: Denken Sie daran, dass die Quelldateiname geht in die nicht gestrippte Binärdatei, sodass zwei Programme, die aus unterschiedlich benannten Quelldateien stammen, unterschiedliche Hashes haben.
In ähnlichen Situationen sollte das oben Gesagte nicht zutreffenDu kannst es versuchen:
laufend strip gegen die Binärdatei, um etwas Fett zu entfernen. Wenn die entfernten Binärdateien dieselben sind, dann waren es einige Metadaten, die für den Programmbetrieb nicht wesentlich sind.
Generieren einer Assembly-Zwischenausgabe, um zu überprüfen, ob der Unterschied nicht in den eigentlichen CPU-Anweisungen liegt (oder um besser zu lokalisieren, wo der Unterschied tatsächlich liegt ist)
verwenden strings, oder geben Sie beide Programme in Hex aus und führen Sie einen Diff auf den beiden Hex-Dumps aus. Sobald Sie die Unterschiede gefunden haben, können Sie versuchen zu sehen, ob sie einen Reim oder Grund haben (PID, Zeitstempel, Zeitstempel der Quelldatei …). Beispielsweise könnten Sie eine Routine haben, die den Zeitstempel zur Kompilierzeit zu Diagnosezwecken speichert.
Mein System ist gcc (GCC) 5.2.0 und Linux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux
– Registrierter Nutzer
4. September 2015 um 15:09 Uhr
Du solltest es versuchen eigentlich Erstellen von zwei separaten Dateien. Ich konnte es auch nicht reproduzieren, indem ich eine einzelne Datei änderte.
– Cyphar
4. September 2015 um 15:10 Uhr
Ja, Dateinamen sind schuld. Ich kann dieselben MD5-Summen erhalten, wenn ich die Programme mit demselben Namen kompiliere.
– Registrierter Nutzer
4. September 2015 um 15:17 Uhr
14220400cookie-checkWarum stimmen zwei Binärdateien von Programmen mit nur geänderten Kommentaren nicht genau in gcc überein?yes
Bitte geben Sie Ihre genauen Befehlszeilen-Flags an. Sind zum Beispiel Debug-Informationen überhaupt in den Binärdateien enthalten? Wenn ja, würde sich die Änderung der Zeilennummern offensichtlich darauf auswirken …
– Jon Skeet
4. September 2015 um 14:51 Uhr
Ist die MD5-Summe über mehrere Builds desselben Codes konsistent?
– wenig begeisterter Benutzer
4. September 2015 um 14:51 Uhr
Ich kann das nicht reproduzieren. Ich hätte vermutet, dass dies daran liegt, dass der GCC beim Kompilieren eine ganze Reihe von Metadaten in Binärdateien einbettet (einschließlich Zeitstempel). Wenn Sie das hinzufügen könnten präzise Befehlszeilen-Flags, die Sie verwendet haben, das wird nützlich sein.
– Cyphar
4. September 2015 um 14:53 Uhr
Anstatt nur MD5-Summen zu überprüfen und hängen zu bleiben, hexdump und diff, um genau zu sehen, welche Bytes sich unterscheiden
– MM
5. September 2015 um 10:39 Uhr
Obwohl die Antwort auf die Frage “Was ist der Unterschied zwischen den beiden Compilerausgaben?” Interessant ist, stelle ich fest, dass die Frage eine ungerechtfertigte Annahme hat: dass die beiden Ausgänge sollte gleich sein und dass wir welche benötigen Erläuterung warum sie anders sind. Alles, was der Compiler Ihnen verspricht, ist, dass, wenn Sie ihm ein legales C-Programm geben, die Ausgabe eine legale ausführbare Datei ist, die dieses Programm implementiert. Dass zwei beliebige Ausführungen des Compilers dieselbe Binärdatei erzeugen, ist keine Garantie des C-Standards.
– Eric Lippert
5. September 2015 um 18:47 Uhr