Você consegue pensar em algum uso legítimo (inteligente) para modificação de código de tempo de execução (programa modificando seu próprio código em tempo de execução)?
Os sistemas operacionais modernos parecem desaprovam programas que fazem isso, pois essa técnica foi usada por vírus para evitar a detecção.
Tudo o que consigo pensar é em algum tipo de otimização de tempo de execução que removeria ou acrescentaria algum código sabendo algo em tempo de execução que não pode ser conhecido em tempo de compilação.
Respostas:
Existem muitos casos válidos para modificação de código. A geração de código em tempo de execução pode ser útil para:
Às vezes, o código é traduzido em código em tempo de execução (isso é chamado de tradução binária dinâmica ):
A modificação do código pode ser usada para solucionar as limitações do conjunto de instruções:
Mais casos de modificação de código:
fonte
Isso foi feito em computação gráfica, especificamente em renderizadores de software para fins de otimização. No tempo de execução, o estado de muitos parâmetros é examinado e uma versão otimizada do código do rasterizador é gerada (potencialmente eliminando muitos condicionais), o que permite renderizar primitivos gráficos, por exemplo, triângulos muito mais rapidamente.
fonte
Uma razão válida é porque o conjunto de instruções asm carece de algumas instruções necessárias, que você mesmo pode construir . Exemplo: No x86, não há como criar uma interrupção para uma variável em um registro (por exemplo, interromper com o número da interrupção no machado). Somente números const codificados no opcode foram permitidos. Com o código auto-modificador, pode-se imitar esse comportamento.
fonte
Alguns compiladores costumavam usá-lo para inicialização de variável estática, evitando o custo de uma condicional para acessos subseqüentes. Em outras palavras, eles implementam "execute este código apenas uma vez" substituindo esse código por no-ops na primeira vez em que é executado.
fonte
Existem muitos casos:
Alguns modelos de segurança de sistemas operacionais significam que o código auto-modificável não pode ser executado sem privilégios de administrador / root, tornando-o impraticável para uso geral.
Da Wikipedia:
Nesses sistemas operacionais, mesmo programas como a Java VM precisam de privilégios root / admin para executar seu código JIT. (Veja http://en.wikipedia.org/wiki/W%5EX para mais detalhes)
fonte
O SO Synthesis basicamente avaliou parcialmente seu programa com relação às chamadas de API e substituiu o código do SO pelos resultados. O principal benefício é que muitas verificações de erros desapareceram (porque se o seu programa não solicitar ao sistema operacional que faça algo estúpido, não será necessário verificar).
Sim, esse é um exemplo de otimização de tempo de execução.
fonte
Muitos anos atrás, passei uma manhã tentando depurar algum código auto-modificável; uma instrução alterou o endereço de destino da instrução a seguir, ou seja, eu estava computando um endereço de filial. Foi escrito em linguagem assembly e funcionou perfeitamente quando eu percorri o programa, uma instrução de cada vez. Mas quando eu executei o programa falhou. Eventualmente, eu percebi que a máquina estava buscando 2 instruções da memória e (como as instruções foram dispostas na memória) a instrução que eu estava modificando já havia sido buscada e, portanto, a máquina estava executando a versão não modificada (incorreta) da instrução. Obviamente, quando eu estava depurando, ele fazia apenas uma instrução por vez.
Meu ponto de vista, o código auto-modificável pode ser extremamente desagradável para testar / depurar e muitas vezes tem suposições ocultas quanto ao comportamento da máquina (seja hardware ou virtual). Além disso, o sistema nunca pôde compartilhar páginas de código entre os vários threads / processos em execução nas (agora) máquinas com vários núcleos. Isso anula muitos dos benefícios da memória virtual, etc. Também invalidaria as otimizações de ramificações feitas no nível do hardware.
(Nota - eu não incluí o JIT na categoria de código auto-modificável. O JIT está traduzindo de uma representação do código para uma representação alternativa, não está modificando o código)
No geral, é apenas uma péssima idéia - muito legal, muito obscura, mas muito ruim.
é claro - se tudo o que você tem são 8080 e ~ 512 bytes de memória, talvez seja necessário recorrer a essas práticas.
fonte
Do ponto de vista de um kernel do sistema operacional, todo o Just In Time Compiler e Linker Runtime executam a auto-modificação do texto do programa. Um exemplo importante seria o V8 ECMA Script Interpreter do Google.
fonte
Outro motivo do código de modificação automática (na verdade, um código de "geração automática") é implementar um mecanismo de compilação Just-in-time para desempenho. Por exemplo, um programa que lê uma expressão algébrica e a calcula em vários parâmetros de entrada pode converter a expressão em código de máquina antes de declarar o cálculo.
fonte
Você sabe a velha opinião que não há diferença lógica entre hardware e software ... também se pode dizer que não há diferença lógica entre código e dados.
O que é código de modificação automática? Código que coloca valores no fluxo de execução para que possa ser interpretado não como dados, mas como um comando. Certamente, existe o ponto de vista teórico nas linguagens funcionais de que realmente não há diferença. Estou dizendo que podemos fazer isso de maneira direta em linguagens imperativas e compiladores / intérpretes sem a presunção de status igual.
Estou me referindo no sentido prático de que os dados podem alterar os caminhos de execução do programa (em algum sentido, isso é extremamente óbvio). Estou pensando em algo como um compilador-compilador que cria uma tabela (uma matriz de dados) que se percorre na análise, passando de estado para estado (e também modificando outras variáveis), assim como um programa se move de comando para comando , modificando variáveis no processo.
Portanto, mesmo na instância usual de onde um compilador cria espaço para código e se refere a um espaço para dados totalmente separado (a pilha), ainda é possível modificar os dados para alterar explicitamente o caminho da execução.
fonte
Eu implementei um programa usando evolução para criar o melhor algoritmo. Ele usou código auto-modificador para modificar o modelo de DNA.
fonte
Um caso de uso é o arquivo de teste EICAR, que é um arquivo COM executável legítimo do DOS para testar programas antivírus.
Ele precisa usar a modificação de código próprio, porque o arquivo executável deve conter apenas caracteres ASCII imprimíveis / tipáveis no intervalo [21h-60h, 7Bh-7Dh], o que limita significativamente o número de instruções codificáveis.
Os detalhes são explicados aqui
Também é usado para o envio de operações de ponto flutuante no DOS
Alguns compiladores serão emitidos
CD xx
com xx variando de 0x34-0x3B em locais de instruções de ponto flutuante x87. ComoCD
é o opcode paraint
instruções, ele pulará para a interrupção 34h-3Bh e emulará essa instrução no software se o coprocessador x87 não estiver disponível. Caso contrário, o manipulador de interrupção substituirá esses 2 bytes por,9B Dx
para que as execuções posteriores sejam tratadas diretamente por x87 sem emulação.Qual é o protocolo para emulação de ponto flutuante x87 no MS-DOS?
fonte
O kernel do Linux possui módulos carregáveis do kernel que fazem exatamente isso.
O Emacs também tem essa capacidade e eu o uso o tempo todo.
Qualquer coisa que suporte uma arquitetura de plug-in dinâmico está essencialmente modificando seu código em tempo de execução.
fonte
Eu executo análises estatísticas em um banco de dados atualizado continuamente. Meu modelo estatístico é gravado e reescrito toda vez que o código é executado para acomodar novos dados que se tornam disponíveis.
fonte
O cenário em que isso pode ser usado é um programa de aprendizado. Em resposta à entrada do usuário, o programa aprende um novo algoritmo:
Há uma pergunta sobre como fazer isso em Java: Quais são as possibilidades de auto-modificação do código Java?
fonte
A melhor versão disso pode ser as macros Lisp. Diferentemente das macros C, que são apenas um pré-processador, o Lisp permite que você tenha acesso a toda a linguagem de programação o tempo todo. Este é o recurso mais poderoso do lisp e não existe em nenhum outro idioma.
Eu não sou um especialista, mas chame um dos cegos falando sobre isso! Há uma razão para eles dizerem que o Lisp é a linguagem mais poderosa e as pessoas inteligentes, não que provavelmente estejam certas.
fonte