Gdybym miał skompilować program do pojedynczego pliku binarnego, zrobić sumę kontrolną, a następnie ponownie skompilować na tym samym komputerze z tymi samymi ustawieniami kompilatora i kompilatora oraz sumą kontrolną zrekompilowanego programu, czy suma kontrolna się nie powiedzie?
Jeśli tak, to dlaczego? Jeśli nie, czy posiadanie innego procesora skutkowałoby nieidentycznym plikiem binarnym?
Odpowiedzi:
Skompiluj ten sam program z tymi samymi ustawieniami na tym samym komputerze:
Chociaż ostateczna odpowiedź brzmi „zależy”, uzasadnione jest oczekiwanie, że większość kompilatorów będzie deterministyczna przez większość czasu i że utworzone pliki binarne powinny być identyczne. Rzeczywiście, niektóre systemy kontroli wersji zależą od tego. Jednak zawsze są wyjątki; jest całkiem możliwe, że jakiś kompilator gdzieś zdecyduje się wstawić znacznik czasu lub coś takiego (na przykład iirc, Delphi). Lub sam proces kompilacji może to zrobić; Widziałem makefile dla programów w C, które ustawiają makro preprocesora na bieżący znacznik czasu. (Wydaje mi się, że byłoby to inne ustawienie kompilatora.)
Pamiętaj również, że jeśli statycznie podłączysz plik binarny, wówczas skutecznie uwzględnisz stan wszystkich odpowiednich bibliotek na komputerze, a wszelkie zmiany w dowolnej z nich wpłyną również na twój plik binarny. Tak więc istotne są nie tylko ustawienia kompilatora.
Skompiluj ten sam program na innym komputerze z innym procesorem.
Tutaj wszystkie zakłady są wyłączone. Większość nowoczesnych kompilatorów jest w stanie dokonywać optymalizacji specyficznych dla celu; jeśli ta opcja jest włączona, pliki binarne mogą się różnić, chyba że procesory są podobne (i nawet wtedy jest to możliwe). Zobacz także powyższą uwagę na temat łączenia statycznego: środowisko konfiguracyjne wykracza daleko poza ustawienia kompilatora. O ile nie masz bardzo ścisłej kontroli konfiguracji, jest bardzo prawdopodobne, że coś różni się między tymi dwiema maszynami.
źródło
gcc -c
może być identyczny, ale powiązane wersje różnią się. Poza tym to nie tylko-march
; są też-mtune/-mcpu
i-mfpmatch
(i ewentualnie inne). Niektóre z nich mogą mieć różne ustawienia domyślne w różnych instalacjach, więc może być konieczne jawne wymuszenie najgorszego możliwego przypadku dla twoich komputerów; może to znacznie obniżyć wydajność, szczególnie jeśli powrócisz do i386 bez sse. I oczywiście, jeśli jeden z twoich procesorów jest ARM, a drugi i686 ...To, o co pytasz, to „ deterministyczny wynik ”. Jeśli skompilowałeś program raz, natychmiast skompiluj go ponownie, prawdopodobnie uzyskasz ten sam plik wyjściowy. Jednak jeśli cokolwiek się zmieniło - nawet niewielka zmiana - szczególnie w komponencie, którego używa skompilowany program, to wyjście kompilatora może się również zmienić.
źródło
-frandom-seed=string
.Dla wszystkich kompilatorów? Nie. Kompilator C # przynajmniej nie jest dozwolony.
Eric Lippert szczegółowo analizuje, dlaczego dane wyjściowe kompilatora nie są deterministyczne .
Chociaż jest to specyficzne dla wersji kompilatora C #, wiele punktów w artykule można zastosować do dowolnego kompilatora.
źródło
-frandom-seed=123
kontroluje losowość wewnętrzną GCC.man gcc
mówi:__FILE__
: umieść źródło w stałym folderze (np./tmp/build
)__DATE__
,__TIME__
,__TIMESTAMP__
:-D
-Wdate-time
lub-Werror=date-time
: ostrzegaj lub zawieść, jeśli albo__TIME__
,__DATE__
albo__TIMESTAMP__
są używane. Jądro Linux 4.4 używa go domyślnie.D
flagi zar
lub użyj https://github.com/nh2/ar-timestamp-wiper/tree/master do wycierania znaczków-fno-guess-branch-probability
: starsze wersje podręczników mówią, że jest to źródło niedeterminizmu, ale już nie . Nie jestem pewien, czy jest to objęte,-frandom-seed
czy nie.Debian Reproducible buduje próby standaryzacji pakietów Debiana bajt po bajcie, a ostatnio otrzymał grant Linux Foundation . Obejmuje to coś więcej niż tylko kompilację, ale powinno być interesujące.
Buildroot ma
BR2_REPRODUCIBLE
opcję, która może dać pewne pomysły na poziomie pakietu, ale na tym etapie nie jest jeszcze ukończona.Powiązane wątki:
źródło
Projekt https://reproducible-builds.org/ dotyczy właśnie tego i stara się znaleźć odpowiedź na pytanie „nie, nie będą się różnić” w jak największej liczbie miejsc. NixOS i Debian mają teraz ponad 90% odtwarzalności swoich pakietów.
Jeśli skompilujesz plik binarny, a ja skompiluję plik binarny, a są one identyczne bit po bicie, to mogę być pewny, że kod źródłowy i narzędzia są tym, co określa dane wyjściowe, i że nie zakradłeś się po drodze kod trojana.
Jeśli połączymy odtwarzalność z możliwością rozruchu ze źródła czytelnego dla człowieka, jak działa http://bootstrappable.org/ , otrzymujemy system określony od podstaw przez źródło czytelne dla człowieka, i dopiero wtedy jesteśmy w punkcie, w którym możemy ufać, że wiemy, co robi system.
źródło
Powiedziałbym NIE, to nie jest w 100% deterministyczne. Wcześniej współpracowałem z wersją GCC, która generuje docelowe pliki binarne dla procesora Hitachi H8.
Nie ma problemu ze znacznikiem czasu. Nawet jeśli kwestia znacznika czasu zostanie zignorowana, określona architektura procesora może pozwolić na zakodowanie tej samej instrukcji na 2 nieco inne sposoby, przy czym niektóre bity mogą mieć wartość 1 lub 0. Moje wcześniejsze doświadczenia pokazują, że wygenerowane pliki binarne były w tej samej chwili WIĘCEJ ale czasami gcc generuje pliki binarne o identycznym rozmiarze, ale niektóre bajty różnią się tylko 1 bitem, np. 0XE0 staje się 0XE1.
źródło
Ogólnie nie. Najbardziej rozsądne kompilatory uwzględnią czas kompilacji w module obiektowym. Nawet jeśli zresetujesz zegar, musisz być bardzo dokładny w odniesieniu do momentu rozpoczęcia kompilacji (a następnie mieć nadzieję, że dostęp do dysku itp. Był taki sam jak wcześniej).
źródło