Se eu fosse compilar um programa em um único binário, criar uma soma de verificação e recompilar na mesma máquina com as mesmas configurações de compilador e compilador e soma de verificação do programa recompilado, a soma de verificação falharia?
Se sim, por que isso? Caso contrário, ter uma CPU diferente resultaria em um binário não idêntico?
Respostas:
Compile o mesmo programa com as mesmas configurações na mesma máquina:
Embora a resposta definitiva seja "depende", é razoável esperar que a maioria dos compiladores seja determinística na maior parte do tempo e que os binários produzidos sejam idênticos. De fato, alguns sistemas de controle de versão dependem disso. Ainda assim, sempre há exceções; é bem possível que algum compilador em algum lugar decida inserir um carimbo de data / hora ou algo parecido (iirc, Delphi, por exemplo). Ou o próprio processo de compilação pode fazer isso; Eu já vi makefiles para programas C que definem uma macro de pré-processador para o timestamp atual. (Eu acho que isso contaria como sendo uma configuração diferente do compilador.)
Além disso, esteja ciente de que se você vincular estaticamente o binário, estará incorporando efetivamente o estado de todas as bibliotecas relevantes em sua máquina, e qualquer alteração em qualquer uma delas também afetará seu binário. Portanto, não são apenas as configurações do compilador que são relevantes.
Compile o mesmo programa em uma máquina diferente com uma CPU diferente.
Aqui, todas as apostas estão fora. A maioria dos compiladores modernos são capazes de fazer otimizações específicas de destino; se essa opção estiver ativada, é provável que os binários sejam diferentes, a menos que as CPUs sejam semelhantes (e mesmo assim, é possível). Além disso, consulte a nota acima sobre links estáticos: o ambiente de configuração vai muito além das configurações do compilador. A menos que você tenha um controle de configuração muito rigoroso, é extremamente provável que algo difira entre as duas máquinas.
fonte
gcc -c
pode muito bem ser idêntica, mas as versões vinculadas diferem. Além disso, não é apenas-march
; existe também-mtune/-mcpu
e-mfpmatch
(e possivelmente outros). Alguns deles podem ter padrões diferentes em instalações diferentes; portanto, você pode precisar forçar explicitamente o pior caso possível para suas máquinas; isso pode reduzir significativamente o desempenho, principalmente se você reverter para o i386 sem a sse. E, claro, se um de seus CPUs é um braço eo outro um i686 ...O que você está perguntando é "é a saída determinística ". Se você compilou o programa uma vez, imediatamente o compilou novamente, provavelmente terminaria com o mesmo arquivo de saída. No entanto, se alguma coisa mudar - mesmo uma pequena alteração - especialmente em um componente usado pelo programa compilado, a saída do compilador também poderá ser alterada.
fonte
-frandom-seed=string
.Para todos os compiladores? Não. O compilador C #, pelo menos, não tem permissão.
Eric Lippert tem um detalhamento completo sobre por que a saída do compilador não é determinística .
Embora seja específico para uma versão do compilador C #, muitos pontos do artigo podem ser aplicados a qualquer compilador.
fonte
-frandom-seed=123
controla alguma aleatoriedade interna do GCC.man gcc
diz:__FILE__
: coloque a fonte em uma pasta fixa (por exemplo/tmp/build
)__DATE__
,__TIME__
,__TIMESTAMP__
:-D
-Wdate-time
ou-Werror=date-time
: avisar ou falhar se quer__TIME__
,__DATE__
ou__TIMESTAMP__
se é usado. O kernel do Linux 4.4 usa-o por padrão.D
bandeira comar
ou https://github.com/nh2/ar-timestamp-wiper/tree/master para limpar carimbos-fno-guess-branch-probability
: versões manuais mais antigas dizem que é uma fonte de não-determinismo, mas não é mais . Não tenho certeza se isso é coberto-frandom-seed
ou não.O projeto Debian Reproducible cria tentativas de padronizar pacotes Debian byte a byte, e recentemente recebeu uma concessão da Linux Foundation . Isso inclui mais do que apenas compilação, mas deve ser de interesse.
O Buildroot tem uma
BR2_REPRODUCIBLE
opção que pode fornecer algumas idéias no nível do pacote, mas ainda está longe de ser concluída.Tópicos relacionados:
fonte
O projeto https://reproducible-builds.org/ trata disso e está se esforçando para responder a sua pergunta "não, eles não diferem" no maior número possível de lugares. NixOS e Debian agora têm mais de 90% de reprodutibilidade para seus pacotes.
Se você compilar um binário, e eu compilar um binário, e eles forem bit a bit idênticos, posso ter certeza de que o código-fonte e as ferramentas são as que determinam a saída e que você não se esgueirou em alguns código de tróia ao longo do caminho.
Se combinarmos a reprodutibilidade com a capacidade de inicialização de fontes legíveis por humanos, como http://bootstrappable.org/ está trabalhando, obteremos um sistema determinado desde o início por fontes legíveis por humanos, e somente então estaremos em um ponto em que podemos confiar que sabemos o que o sistema está fazendo.
fonte
Eu diria que NÃO, não é 100% determinístico. Anteriormente, trabalhei com uma versão do GCC que gera binários de destino para o processador Hitachi H8.
Não é um problema com o carimbo de data / hora. Mesmo que o problema de registro de data e hora seja ignorado, a arquitetura específica do processador pode permitir que a mesma instrução seja codificada de duas maneiras ligeiramente diferentes, onde alguns bits podem ser 1 ou 0. Minha experiência anterior mostra que os binários gerados eram os mesmos na MAIORIA do tempo mas, ocasionalmente, o gcc geraria binários com tamanho idêntico, mas alguns bytes são diferentes em apenas 1 bit, por exemplo, 0XE0 se torna 0XE1.
fonte
Em geral, não. A maioria dos compiladores razoavelmente sofisticados incluirá o tempo de compilação no módulo de objeto. Mesmo se você redefinisse o relógio, teria que ser muito preciso em relação ao momento em que iniciou a compilação (e então espere que os acessos ao disco, etc., tenham a mesma velocidade de antes).
fonte