Neden sadece yorumların değiştiği iki program ikili dosyası gcc ile tam olarak eşleşmiyor?


110

İki C programı oluşturdum

  1. Program 1

    int main()
    {
    }
  2. Program 2

    int main()
    {
    //Some Harmless comments
    }

AFAIK, derleme sırasında, derleyici (gcc) yorumları ve gereksiz beyaz alanları görmezden gelmeli ve bu nedenle çıktı benzer olmalıdır.

Ama çıktı ikili dosyalarının md5 toplamlarını kontrol ettiğimde, eşleşmiyorlar. Ayrıca optimizasyonu ile derleme çalıştı -O3ve -Ofastama yine de eşleşmedi.

Burada ne oluyor?

DÜZENLEME: tam komutlar ve md5 toplamları vardır (t1.c program 1'dir ve t2.c program 2'dir)

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

Ve evet, md5sum'lar aynı bayraklara sahip birden çok derlemede eşleşir.

BTW benim sistemim gcc (GCC) 5.2.0veLinux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux


17
Lütfen tam olarak komut satırı işaretlerinizi ekleyin. Örneğin, hata ayıklama bilgileri ikili dosyalara dahil mi? Öyleyse, değişen satır numaraları açıkça onu etkileyecektir ...
Jon Skeet

4
MD5 toplamı aynı kodun birden çok yapısında tutarlı mı?
unenthusiasticuser

3
Bunu yeniden üretemiyorum. Bunun, GCC'nin, onları derlerken (zaman damgaları dahil) bir sürü meta veriyi ikili dosyalara yerleştirmesinden kaynaklandığını tahmin etmiştim. Kullandığınız kesin komut satırı bayraklarını ekleyebilirseniz , bu yararlı olacaktır.
cyphar

2
Yalnızca MD5 toplamlarını kontrol etmek ve takılıp kalmak yerine, hangi baytların farklı olduğunu görmek için onaltılık döküm ve fark
MM

12
"İki derleyici çıktısı arasında ne fark var?" Sorusunun cevabı olsa da. ilginçtir, sorunun haksız bir varsayımı olduğunu not ediyorum: iki çıktının aynı olması gerektiği ve neden farklı olduklarına dair bazı açıklamalara ihtiyacımız var . Derleyicinin size vaat ettiği tek şey, ona yasal bir C programı verdiğinizde, çıktının bu programı uygulayan yasal bir yürütülebilir dosya olmasıdır. Derleyicinin herhangi iki uygulamasının aynı ikiliyi ürettiği, C standardının garantisi değildir.
Eric Lippert

Yanıtlar:


159

Bunun nedeni dosya adlarının farklı olmasıdır (dizelerin çıktısı aynı olsa da). Dosyanın kendisini değiştirmeyi denerseniz (iki dosyaya sahip olmak yerine), çıktı ikili dosyalarının artık farklı olmadığını fark edeceksiniz. Hem Jens hem de benim dediğimiz gibi, bunun nedeni GCC'nin , tam kaynak dosya adı da dahil olmak üzere (ve AFAICS de clang) oluşturduğu ikili dosyalara tüm meta verileri atmasıdır.

Bunu dene:

$ 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

Bu, md5 toplamlarınızın neden derlemeler arasında değişmediğini, ancak farklı dosyalar arasında farklı olduklarını açıklar. İsterseniz, Jens'in önerdiğini yapabilir ve stringsher ikili dosya için çıktılarını karşılaştırabilirsiniz , dosya adlarının ikili dosyada gömülü olduğunu fark edeceksiniz. Bunu "düzeltmek" istiyorsanız strip, ikili dosyaları yapabilirsiniz ve meta veriler kaldırılacaktır:

$ 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

DÜZENLEME: Sorunu "düzeltmek" için ikili dosyaları çıkarabileceğinizi söyleyecek şekilde güncellendi.
cyphar

30
Bu nedenle MD5 sağlama toplamlarını değil, montaj çıktısını karşılaştırmalısınız.
Orbit'te Hafiflik Yarışları

1
Burada bir takip sorusu sordum .
Federico Poloni

4
Nesne dosyası formatına bağlı olarak, derleme süresi nesne dosyalarında da saklanır. Dolayısıyla, örneğin a ve a2 dosyaları gibi COFF dosyalarını kullanmak aynı olmayacaktır.
Martin Rosenau

28

En yaygın neden, derleyici tarafından eklenen dosya adları ve zaman damgalarıdır (genellikle ELF bölümlerinin hata ayıklama bilgileri bölümünde).

Koşmayı dene

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

ve sebebini görebilirsiniz. Bunu bir keresinde aynı kaynağın farklı dizinlerde derlendiğinde neden farklı koda neden olduğunu bulmak için kullandım. Bulgu, __FILE__makronun her iki ağaçta da farklı olarak mutlak bir dosya adına genişlemesiydi .


1
Gcc.gnu.org/ml/gcc-help/2007-05/msg00138.html'ye göre (eski, biliyorum) zaman damgalarını kaydetmiyorlar ve bu bir bağlayıcı sorunu olabilir. Bununla birlikte, yakın zamanda bir güvenlik firmasının ikili dosyalarında GCC zaman damgası bilgilerini kullanarak bir bilgisayar korsanlığı ekibinin çalışma alışkanlıklarını nasıl profilini çıkardığına dair bir hikaye okuduğumu hatırlıyorum.
cyphar

3
Ve OP'nin "md5sum'ların aynı bayraklara sahip birden çok derlemede eşleştiğini" belirttiğinden bahsetmiyorum bile, bu da soruna muhtemelen neden olan zaman damgaları olmadığını gösterir. Muhtemelen farklı dosya adları olmasından kaynaklanmaktadır.
cyphar

1
@cyphar Farklı dosya adları, strings / diff yaklaşımıyla da yakalanmalıdır.
Jens

15

Not : kaynak dosya adının dizilmemiş ikili dosyaya girdiğini unutmayın , bu nedenle farklı adlandırılmış kaynak dosyalardan gelen iki programın farklı karmaları olacaktır.

Benzer durumlarda, yukarıdakiler geçerli değilse şunları deneyebilirsiniz:

  • bir stripmiktar yağ çıkarmak için ikiliye karşı çalışıyor . Çıkarılmış ikili dosyalar aynıysa, programın çalışması için gerekli olmayan bazı meta verilerdir.
  • Farkın gerçek CPU talimatlarında olmadığını doğrulamak için (veya farkın gerçekte nerede olduğunu daha iyi belirlemek için ) bir derleme ara çıkışı oluşturma
  • kullanın stringsveya her iki programı onaltılık olarak boşaltın ve iki onaltılık dökümde bir fark çalıştırın. Farkı / farkları bulduktan sonra, kafiye veya neden olup olmadığını deneyebilir ve deneyebilirsiniz (PID, zaman damgaları, kaynak dosya zaman damgası ...). Örneğin , teşhis amacıyla derleme zamanında zaman damgasını saklayan bir rutininiz olabilir .

Sistemim gcc (GCC) 5.2.0veLinux 4.2.0-1-MANJARO #1 SMP PREEMPT x86_64 GNU/Linux
Kayıtlı Kullanıcı

2
Aslında iki ayrı dosya oluşturmayı denemelisiniz . Tek bir dosyayı değiştirerek de yeniden oluşturamadım.
cyphar

Evet, dosya adları suçludur. Programları aynı isimde derlersem aynı md5sum'ları alabilirim.
Kayıtlı Kullanıcı
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.