Bir programın yeniden derlenmesi bit için bire bir aynı ikili dosya üretiyor mu?


25

Bir programı tek bir ikili dosyada derlemek, bir sağlama toplamı yapmak ve daha sonra aynı makinede aynı derleyici ve derleyici ayarlarıyla yeniden derlemek ve yeniden derlenen programın sağlama toplamı, sağlama toplamı başarısız olur mu?

Öyleyse, neden bu? Değilse, farklı bir CPU'ya sahip olmak aynı olmayan bir ikili dosyaya neden olur mu?


8
Derleyiciye bağlıdır. Bazıları zaman damgası koyar, bu yüzden cevap olanlar için "hayır" dır.
ta.speot.is

Aslında bu , derleyiciye değil çalıştırılabilir biçime bağlıdır . Windows 'PE formatı gibi bazı çalıştırılabilir formatlar, derleme saatine ve tarihine dokunan bir zaman damgası içerirken, Linux'un ELF formatı gibi diğer formatlar da yok. Her iki durumda da, bu soru “özdeş ikili” tanımına dayanmaktadır. Aynı kaynak dosya aynı derleyici ve kitaplıklar ve anahtarlar ve her şeyle derlenirse, görüntünün kendisi de birebir aynı olacaktır, ancak başlık ve diğer meta veriler değişebilir.
Synetech

Yanıtlar:


19
  1. Aynı makinede aynı ayarlarla aynı programı derleyin:

    Kesin cevap "bağlıdır" olmasına rağmen, çoğu derleyicinin çoğu zaman deterministik olmasını ve üretilen ikililerin aynı olması gerektiğini beklemek mantıklıdır. Aslında, bazı sürüm kontrol sistemleri buna bağlı. Yine de, her zaman istisnalar vardır; Bir yerdeki bazı derleyicilerin bir zaman damgası veya başka bir şey eklemeye karar vermesi oldukça muhtemeldir (örneğin, iirc, Delphi yapar). Veya derleme işleminin kendisi bunu yapabilir; Geçerli zaman damgasına bir önişlemci makrosu ayarlayan C programları için makefiles gördüm. (Sanırım, bunun farklı bir derleyici ayarı olarak sayılacağını düşünüyorum.)

    Ayrıca, eğer ikiliyi statik olarak bağlarsanız, makinenize ilgili tüm kütüphanelerin durumunu etkili bir şekilde dahil ettiğinizi ve bunlardan herhangi birindeki herhangi bir değişikliğin de ikili sisteminizi etkileyeceğini unutmayın. Bu yüzden sadece ilgili derleyici ayarları değildir.

  2. Aynı programı farklı bir CPU ile farklı bir makinede derleyin.

    Burada, tüm bahisler kapalı. Çoğu modern derleyici, hedefe özgü optimizasyonlar yapabilir; Bu seçenek etkinleştirilirse, CPU'lar benzer olmadığı sürece ikili dosyaların farklı olması muhtemeldir (ve o zaman bile mümkündür). Ayrıca, statik bağlantı hakkında yukarıdaki nota bakın: yapılandırma ortamı derleyici ayarlarının çok ötesine geçer. Çok katı bir konfigürasyon kontrolünüz olmadığı sürece, iki makine arasında bir şeyin farklı olması muhtemeldir.


1
Diyelim ki GCC kullanıyordum ve march seçeneğini kullanmıyordum (ikiliyi belirli bir CPU ailesi için optimize eden seçenek), ve bir CPU ile bir ikiliyi derleyecektim ve sonra başka bir CPU ile bir fark?
David

1
@Didid: Yine de değişir. İlk olarak, bağlantı kurduğunuz kitaplıkların mimariye özgü yapıları olabilir. Bu nedenle çıktısı gcc -caynı olabilir, ancak bağlantılı sürümler farklıdır. Ayrıca, sadece değil -march; Ayrıca -mtune/-mcpu ve -mfpmatch(ve muhtemelen diğerleri) vardır. Bunlardan bazıları farklı kurulumlarda farklı varsayılanlara sahip olabilir, bu nedenle makineleriniz için mümkün olan en kötü durumu açıkça zorlamanız gerekebilir; bunu yapmanız, özellikle sse i386'ya dönme durumunda performansı önemli ölçüde azaltabilir. Ve tabii ki, eğer
cpuslarınızdan

1
Ayrıca GCC, ikili dosyalara zaman damgası ekleyen söz konusu derleyicilerden biri mi?
David

@ david: afaik, hayır.
rici

8

İstediğiniz şey, "çıktı belirleyicidir ". Programı bir kez derlediyseniz, derhal tekrar derleyin, muhtemelen aynı çıktı dosyasına sahip olursunuz. Ancak, bir şey değiştiyse - küçük bir değişiklik olsa bile - özellikle derlenen programın kullandığı bir bileşende, derleyicinin çıktısı da değişebilir.


2
Gerçekten çok iyi bir nokta. Bu makalede bazı çok ilginç gözlemler var. Özellikle, GCC ile derleme olabilir değil o içten bir rasgele sayı üreteci kullandığı için anonim ad, içinde işlevlerini mangles nasıl örneğin bazı durumlarda girdiler açısından, ile deterministik olmak. Bu özel durumda determinizm elde etmek için, seçeneği belirterek bir ilk rastgele tohum tedarik edin -frandom-seed=string.
ack

7

Bir programın yeniden derlenmesi bit için bire bir aynı ikili dosya üretiyor mu?

Tüm derleyiciler için? Hayır. En azından C # derleyicisine izin verilmiyor.

Eric Lippert, derleyicinin çıktısının neden belirleyici olmadığına dair çok ayrıntılı bir döküme sahiptir .

[T] C # derleyicisi tasarım gereği asla aynı ikili dosyayı iki kere üretmez. C # derleyicisi her montajda, her çalıştırışınızda yeni oluşturulan bir GUID'yi yerleştirir, böylece hiçbir iki düzeneğin bit için birebir aynı olmamasını sağlar. CLI şartnamesinden alıntı yapmak için:

Mvid sütunu, modülün bu örneğini tanımlayan benzersiz bir GUID [...] dizine alır. [...] Mvid her modül için yeni oluşturulmalıdır [...] [çalışma zamanı] Mvid’ten hiçbir şekilde faydalanmasa da, diğer araçlar (hata ayıklayıcılar [...] gibi) kullanımına dayanır. Mvid neredeyse her zaman bir modülden diğerine farklılık gösterir.

C # derleyicisinin bir sürümüne özgü olmasına rağmen, makaledeki birçok nokta herhangi bir derleyiciye uygulanabilir .

Öncelikle, her zaman aynı sırada her zaman aynı dosya listesini aldığımızı varsayıyoruz. Ancak bu, bazı durumlarda işletim sistemine bağlı. "Csc * .cs" deyince, işletim sisteminin eşleşen dosyalar listesini sağladığı sıra, işletim sisteminin bir uygulama detayıdır; derleyici bu listeyi kurallı bir sıraya göre sıralamaz.


Yapılışı yeniden üretilebilir hale getirmek zor olmamalıdır (derleme zamanı ve montaj GUID'i gibi kolayca atılabilen birkaç alan dışında). Örneğin, giriş dosyalarını kanonik bir düzende sıralamak tek bir astardır. Bu GUID bile, yeni oluşturulanlar yerine montajın kalanının bir karması olabilir.
CodesInChaos

Microsoft C # derleyicisini kastediyorsunuz ya da şartname şartı mı?
David

@David CLI spec gerektirir. Mono'nun C # derleyicisi aynı şeyi yapmak zorunda kalacaktı. Herhangi bir VB .NET derleyici için aynı.
ta.speot.is

4
ECMA standardında zaman damgası veya MVID farklılığı olması gerekmez. Bunlar olmadan, en azından C # 'da aynı ikili dosyalar için mümkündür. Bu yüzden asıl sebep sorgulanabilir bir tasarım kararıdır ve gerçek bir teknik kısıtlama değildir.
Shiv

7
  • -frandom-seed=123Bazı GCC iç rastgeleliklerini kontrol eder. man gccdiyor:

    Bu seçenek, GCC'nin her derlenmiş dosyada farklı olması gereken belirli sembol isimlerinin üretilmesinde rastgele sayılar yerine kullandığı bir tohum sağlar. Ayrıca kapsama veri dosyalarına ve bunları üreten nesne dosyalarına benzersiz damgalar yerleştirmek için kullanılır. Tekrar üretilebilir özdeş nesneler üretmek için -frandom-seed seçeneğini kullanabilirsiniz.

  • __FILE__: kaynağı sabit bir klasöre koy (örneğin /tmp/build)

  • için __DATE__, __TIME__, __TIMESTAMP__:
    • libfaketime: https://github.com/wolfcw/libfaketime
    • bu makroları geçersiz kıl -D
    • -Wdate-timeya da -Werror=date-time: uyarmak ya da ya da başarısız __TIME__, __DATE__ya da __TIMESTAMP__kullanılan edilir. Linux çekirdeği 4.4 varsayılan olarak kullanır.
  • kullanmak Dişaretleyin arveya kullanım https://github.com/nh2/ar-timestamp-wiper/tree/master pulları temizlemek için
  • -fno-guess-branch-probability: Eski manuel versiyonlar bunun determinizm dışı bir kaynak olduğunu söylüyor, ancak artık değil . Bunun kapsamına girip -frandom-seedgirmediğinden emin değilsin.

Debian Reproducible, Debian paketlerini byte by-by standardize etmeye yönelik proje çalışmaları başlattı ve son zamanlarda bir Linux Foundation hibesi aldı . Bu sadece derlemeden daha fazlasını içerir, fakat ilgi çekici olmalıdır.

Buildroot , BR2_REPRODUCIBLEpaket düzeyinde bazı fikirler verebilecek bir seçeneğe sahiptir, ancak bu noktada tam olmaktan uzaktır.

İlgili konular:


3

Https://reproducible-builds.org/ projesi tamamen bununla ilgili ve "hayır, onlar farklı olmayacak" sorunuzun cevabını mümkün olduğu kadar çok yerde cevaplamak için çok çalışıyor. NixOS ve Debian şimdi paketlerinde tekrarlanabilirlik konusunda% 90'ın üzerinde.

Bir ikiliyi derlerseniz ve ben bir ikiliyi derlersem ve bit bitleri için birebir eşleşirlerse, kaynak kodunun ve araçların çıktıyı belirleyen ve bazı durumlarda gizlice girmediğinizden emin olabilirim. yol boyunca trojan kodu.

Tekrarlanabilirliği insan tarafından okunabilir bir kaynaktan gelen bootstrappability ile birleştirirsek, http://bootstrappable.org/ yapmaya çalışıyorsa, yerden okunabilir bir kaynak tarafından belirlenen bir sistemi elde ederiz, ancak o zaman biz sadece sistemin ne yaptığını bildiğimize güvenebiliriz.


1
Güzel linkler. Ben bir Buildroot fanatiğiyim, ama eğer biri bana QEMU'yu çizen bir Nix ARM çapraz kemer düzeneği verirse, mutlu olacağım :-)
Ciro Santilli 改造 45 中心 法轮功 六四 事件

Guix'ten bahsetmedim çünkü sayılarını nerede bulacağımı bilmiyorum, ancak doğrulama araçlarıyla tekrarlanabilirlik treninde NixOS'tan önce olduklarından eminim, bu yüzden eşit düzeyde ya da daha iyi durumda olduklarından eminim.
clacke

2

HAYIR derdim,% 100 deterministik değil. Daha önce Hitachi H8 işlemcisi için hedef ikili üreten GCC sürümü ile çalıştım.

Bu zaman damgası ile ilgili bir sorun değil. Zaman damgası sorunu göz ardı edilse bile, belirli işlemci mimarisi aynı komutun bazı bitlerin 1 veya 0 olabileceği 2 farklı şekilde kodlanmasına izin verebilir. fakat bazen gcc aynı büyüklükte ikilik dosyalar üretecektir ancak bazı baytların sadece 1 bitlik farklı olması, örneğin 0XE0, 0XE1 olur.


Ve bu farklı davranışlara ya da “ciddi sorunlara” yol açtı mı?
Florian Straub

1

Genel olarak hayır. En makul düzeyde karmaşık olan derleyiciler, nesne modülündeki derleme süresini içerecektir. Saati sıfırlasanız bile, derlemeyi ne zaman başlattığınıza ilişkin olarak çok doğru olmanız gerekir (ve daha sonra diskin eriştiği, vb. Eskisi ile aynı hızdadır).

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.