A recompilação de um programa produz um binário idêntico bit a bit?

23

Se eu fosse compilar um programa em um único binário, fazer uma soma de verificação e, em seguida, recompilá-lo 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, porque é isso? Se não, ter uma CPU diferente resultaria em um binário não idêntico?

    
por David 01.09.2013 / 01:54

7 respostas

18
  1. 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 determinista a 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 decida inserir um timestamp ou algo assim (iirc, o Delphi, por exemplo). Ou o próprio processo de construção pode fazer isso; Eu vi makefiles para programas em C que definem uma macro de pré-processamento para o timestamp atual. (Eu acho que isso contaria como sendo uma configuração de compilador diferente, no entanto.)

    Além disso, esteja ciente de que, se você vincular estaticamente o binário, estará efetivamente incorporando 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.

  2. Compile o mesmo programa em uma máquina diferente com uma CPU diferente.

    Aqui, todas as apostas estão desativadas. A maioria dos compiladores modernos é capaz de fazer otimizações específicas de destino; Se esta opção estiver habilitada, os binários provavelmente serão diferentes, a menos que as CPUs sejam semelhantes (e, mesmo assim, é possível). Além disso, veja a nota acima sobre a vinculação estática: 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 seja diferente entre as duas máquinas.

por 01.09.2013 / 02:52
8

O que você está perguntando é "é a saída determinista ." Se você compilou o programa uma vez, imediatamente compilou-o novamente, você provavelmente acabaria com o mesmo arquivo de saída. No entanto, se alguma coisa mudou - até mesmo uma pequena alteração - especialmente em um componente que o programa compilado usa, então a saída do compilador também pode mudar.

    
por 01.09.2013 / 04:07
7

Does recompiling a program produce a bit-for-bit identical binary?

Para todos os compiladores? Não. O compilador C #, pelo menos, não tem permissão para.

Eric Lippert tem uma análise minuciosa do porquê saída do compilador não é determinista .

[T]he C# compiler by design never produces the same binary twice. The C# compiler embeds a freshly generated GUID in every assembly, every time you run it, thereby ensuring that no two assemblies are ever bit-for-bit identical. To quote from the CLI specification:

The Mvid column shall index a unique GUID [...] that identifies this instance of the module. [...] The Mvid should be newly generated for every module [...] While the [runtime] itself makes no use of the Mvid, other tools (such as debuggers [...]) rely on the fact that the Mvid almost always differs from one module to another.

Embora seja específico para uma versão do compilador C #, muitos pontos no artigo podem ser aplicados ao qualquer compilador.

First off, we are assuming that we always get the same list of files every time, in the same order. But that's in some cases up to the operating system. When you say "csc *.cs", the order in which the operating system proffers up the list of matching files is an implementation detail of the operating system; the compiler does not sort that list into a canonical order.

    
por 01.09.2013 / 13:23
5
  • -frandom-seed=123 controla alguma aleatoriedade interna do GCC. man gcc diz:

    This option provides a seed that GCC uses in place of random numbers in generating certain symbol names that have to be different in every compiled file. It is also used to place unique stamps in coverage data files and the object files that produce them. You can use the -frandom-seed option to produce reproducibly identical object files.

  • __FILE__ : coloque a origem em uma pasta fixa (por exemplo, /tmp/build )

  • para __DATE__ , __TIME__ , __TIMESTAMP__ :
    • libfaketime: link
    • substitua essas macros por -D
    • -Wdate-time ou -Werror=date-time : avisar ou falhar se __TIME__ , __DATE__ ou __TIMESTAMP__ forem usado. O kernel Linux 4.4 usa por padrão.
  • use o sinal D com ar ou use o link para limpar os carimbos
  • -fno-guess-branch-probability : versões mais antigas do manual dizem que é uma fonte de não -determinismo, mas não mais . Não tenho certeza se isso é coberto por -frandom-seed ou não.

O projeto de compilações reprodutível tenta padronizar os pacotes Debian byte-by-byte, e recentemente obteve um Subsídio da Fundação Linux . Isso inclui mais do que apenas compilação, mas deve ser de interesse.

O Buildroot tem uma opção BR2_REPRODUCIBLE que pode dar algumas idéias sobre o nível do pacote, mas está longe de ser completo neste momento. / p>

Tópicos relacionados:

por 23.06.2016 / 08:34
2

Eu diria NÃO, não é 100% determinista. Eu trabalhei anteriormente com uma versão do GCC que gera binários de destino para o processador Hitachi H8.

Não é um problema com o registro de data e hora. Mesmo se a questão do registro de data e hora for ignorada, 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 a mesma maioria do tempo mas ocasionalmente o gcc geraria binários com tamanho idêntico, mas alguns dos bytes diferentes por apenas 1 bit, por exemplo 0XE0 se torna 0XE1.

    
por 04.03.2014 / 14:06
1

O link do projeto é sobre isso, e está tentando fazer a resposta à sua pergunta "não, eles não serão diferentes "em tantos lugares quanto possível. NixOS e Debian estão agora com mais de 90% de reprodutibilidade para seus pacotes.

Se você compilar um binário, e eu compilar um binário, e eles forem idênticos bit a bit, então eu posso ter certeza de que o código-fonte e as ferramentas são o que determinam a saída, e que você não esgueirar-se em algum código de trojan ao longo do caminho.

Se combinarmos reprodutibilidade com bootstrappability a partir de fontes legíveis, como o link está trabalhando, temos um sistema determinado a partir do zero por fonte legível por humanos, e só então estamos em um ponto em que podemos confiar que sabemos o que o sistema está fazendo.

    
por 14.05.2019 / 22:06
1

Em geral, não. A maioria dos compiladores razoavelmente sofisticados incluirá o tempo de compilação no módulo de objeto. Mesmo se você tivesse que zerar o relógio, você teria que ser muito preciso em relação a quando você começou a compilação (e então esperamos que os acessos ao disco, etc, tenham a mesma velocidade de antes).

    
por 01.09.2013 / 15:12