Sua tarefa é escrever um programa em linguagem de máquina x86 (qualquer versão que você queira) que execute todas as instruções possíveis e depois pare, usando no máximo 32 bytes de código e iniciando com registros zerados.
Você pode assumir qualquer coisa sobre a memória de acesso aleatório que desejar, desde que esteja em um formato utilizável para a máquina x86.
Respostas:
2 524224 instruções
Meu programa:
(Nota técnica: isso é escrito para nasm.
a32
É a sintaxe do nasm para o byte de prefixo de tamanho de endereço alternativo. Para masm, você substituia32
pordefb 0x67
.)Para maior clareza, aqui está o resultado da listagem:
O programa assume que o processador está no modo real e que o programa está localizado na parte inferior de um segmento de 64k de memória que, de outra forma, seria inicializado com zero de todos os bits. Seu design é simples: trate a memória como um único inteiro gigante não assinado e a incremente através de todos os valores possíveis, até reverter para todos os zeros. Repita isso 2 32 vezes. Então pare.
O loop mais interno (linhas 4-6) é responsável por incrementar o número inteiro enorme. Cada iteração adiciona zero ou um a um único byte, dependendo da execução do byte anterior. Observe que cada byte no número inteiro enorme é acessado, independentemente de ter sido alterado ou não, portanto esse loop sempre itera 2 16 a 14 vezes.
A propósito, no caso de você estar se perguntando, esse código ilustra o motivo pelo qual as instruções x86
inc
/dec
não afetam o sinalizador de transporte: apenas para simplificar esse tipo de padrão de transporte de vários bytes. (Esse padrão surgiu com mais frequência nos dias de microprocessadores de 8 bits, quando o conjunto de instruções 8080 original foi definido.)A linha 7 faz com que o processo de incremento se repita até que um seja executado no último byte, indicando que o número inteiro enorme foi redefinido para todos os bits-zero. Isso leva muito tempo.
As linhas 8‒9 marcam o loop mais externo e fazem com que esse processo se repita 2 32 vezes, até o
ecx
registro rolar para zero. Isso é efetivamente equivalente a adicionar outros 32 bits ao número inteiro gigante.Seria possível adicionar outro loop externo e fazer isso novamente usando (digamos) o
edx
registrador e, talvez, usandoesi
eedi
para ainda mais repetições. No entanto, não vale a pena fazer. As instruções para incrementar e fazer loop exigem quatro bytes. Esses quatro bytes são retirados do número inteiro gigante. Portanto, perdemos 32 bits no contador de RAM, apenas para adicionar 32 bits através de um registro: acaba sendo uma lavagem. O único motivoecx
é uma exceção: ele possui umaloop
instrução especializada que se encaixa em apenas três bytes. Assim, o programa troca 24 bits por 32, um ganho pequeno, mas ainda positivo, de 8 bits.Não é muito difícil calcular diretamente o número de instruções que o programa executa antes de parar. No entanto, há uma maneira muito mais simples de estimar esse número. Os modifica programa de toda a sua memória, menos os 14 bytes que contêm o programa, e os
bx
eecx
registros. Isso adiciona até 2 16 - 14 + 2 + 4 = 65528 bytes, para um total de 524224 bits. O atalho envolve perceber que, no processo de execução, todos os padrões possíveis de 524224 bits aparecem exatamente uma vez. Para a RAM e oecx
registro, é fácil ver isso, pois o programa aumenta em cada valor. Parabx
isso é um pouco menos óbvio, pois está sendo alterado ao mesmo tempo em que o valor na memória está sendo atualizado. No entanto, pode-se mostrar que, dada a estrutura do programa, se um padrão de bits completo realmente aparecer duas vezes, o programa deverá estar em um loop infinito. Como esse não é o caso, cada padrão de bits deve ser visitado apenas uma vez. (A prova completa é deixada como exercício para o leitor, naturalmente.)Como todo padrão de bits possível aparece no decorrer do programa, o programa deve executar pelo menos 2 instruções 524224 , o que é aproximadamente igual a 1,4 × 10 157807 . (O número acutal é muito ligeiramente maior, por causa das instruções de salto, mas a diferença nessa magnitude é insignificante.)
Obviamente, isso poderia ser significativamente aprimorado usando mais de 64k de RAM. Estou adiando a próxima versão do código até descobrir exatamente quanta RAM pode ser acessada.
fonte
~ 2 ^ (2 ^ 67) instruções
(na sintaxe t)
Desmontado, 26 bytes:
Semelhante à solução da breadbox, mas não há razão para parar com 16 bits de endereço. Meu código usa x86-64 e assume que temos 2 ^ 64 bytes de memória e usamos quase toda a memória que contém o código como um contador gigante.
fonte