Do prompt direto para o binário
Executável byte a byte soa como provocação, mas é exatamente o que aconteceu aqui. Sem linguagem fonte, sem compilador, sem assembler, sem linker. Você entrega uma especificação em linguagem natural para um LLM e recebe de volta os bytes de um ELF pronto para rodar, com header, program header e código de máquina escritos à mão pelo modelo. O único intermediário entre a resposta e o binário é um xxd -r para converter hex em arquivo executável. Quando testei mentalmente esse fluxo, a primeira reação foi de desconfiança, porque a gente está acostumado a pensar em compilação como um pipeline sagrado e cheio de etapas determinísticas. Ver esse pipeline colapsar em uma chamada de modelo quebra um pressuposto básico de quem opera sistemas.
O fato sem enfeite
O experimento vem rodando há alguns anos a cada lançamento de modelo novo, e só agora ficou bom o suficiente para mostrar. O resultado mais forte é um servidor HTTP de 439 bytes, gerado a partir de um parágrafo de especificação, que responde de verdade a um curl. Não é mock, não é simulação, é o binário gerado atendendo request. No outro extremo do espectro, tem um hello world completo de 165 bytes, também byte a byte, e um Tetris jogável em assembly com cerca de 8 KB, sem libc, falando com o servidor X via socket Unix e validado por comparação de screenshots em quatro momentos, spawn da peça, movimento, rotação e trava com limpeza de linha. Controles simples, tecla a para esquerda, d para direita, s para descer e w para girar, com foco por clique na janela.
O loop que faz isso é constrangedoramente simples, um script bash com cerca de 100 linhas. Ele manda a spec para o modelo, pega o retorno, converte em binário e testa de verdade, executa o arquivo, manda curl se for servidor ou compara screenshot se for jogo. Se falhar, devolve o erro cru, exit code, saída, o que o readelf enxerga no arquivo, e tenta de novo até passar ou estourar o orçamento de tentativas. Ninguém fica no meio. O mesmo loop roda em três níveis para medir até onde o modelo desce na pilha sem humano, nível C, nível assembly e nível bytes crus. Com várias tentativas, ele consegue gerar programa funcional nos três níveis, mas no nível mais baixo a confiabilidade cai bastante.
Como funciona na visão de quem opera
Pensa nisso como um compilador probabilístico com verificação determinística. A arquitetura não é só o LLM, é LLM mais harness de teste. O modelo propõe bytes, o sistema operacional dispõe. O fluxo é spec para modelo, modelo para hex, hex para ELF via xxd, ELF para execução real, erro real de volta para o modelo. Esse detalhe muda tudo, porque sem feedback de execução o modelo alucina header e trava em segfault sem aprender nada. O autor descobriu isso do jeito difícil, nas primeiras tentativas em x86-64 tudo falhou, 8 de 8 no hello world e 15 de 15 no servidor, por causa de um dígito hex extra no meio de uma sequência de zeros no header. Tudo depois daquele ponto deslocou meio byte, o readelf ainda via um ELF válido mas com tamanhos absurdos, e a execução só cuspia segfault.
Segfault não ensina ninguém, então ele começou a devolver mais contexto, tamanho real do arquivo e o que o readelf decodifica de fato, entry point, FileSiz, MemSiz e companhia. Aí começou a passar. Ele mesmo admite que não mediu com rigor quanto foi a mudança e quanto foi sorte, e os logs falhos ficaram guardados. Em termos de operação, dá para inferir o custo e a latência, cada iteração é uma chamada longa de modelo com janela grande, mais spin de processo local, curl e inspeção de binário. Nos números relatados com Claude Sonnet 5.5 em x86-64, foram 5 a 6 tentativas de orçamento para C, 6 a 8 para assembly e 8 a 15 para bytes crus, com mediana de tentativas nos casos que passaram de 1 a 2 para C e assembly, 1 para hello world em bytes e 5 para servidor em bytes. Ou seja, latência imprevisível e custo variável, você paga pela teimosia do loop até ele acertar o alinhamento.
Por que o tamanho importa tanto
Comparado com um C estaticamente linkado, esses binários não usam biblioteca nenhuma, então ficam minúsculos. O hello world em C dinamicamente linkado via gcc tem por volta de 15 KB, mas depende de libc e loader dinâmico que não entram na conta. As versões em assembly ficam com 8 a 9 KB muito por padding que o ld adiciona para alinhar em páginas de 4 KB, sendo que o código real do hello tem 47 bytes. Com musl o C estático encolheria bem, o autor não mediu. O ponto de operador aqui é direto, tamanho menor significa menos superfície, startup mais rápido e deploy trivial, mas também significa zero abstração, zero proteção e depuração no osso. Um servidor de 439 bytes contra cerca de 700 KB de uma alternativa convencional mostra o abismo, porém esconde que um cuida de edge cases e o outro mal responde o caminho feliz.
O que isso muda na prática
Quem ganha com isso agora não é quem quer trocar gcc por prompt, é quem constrói tooling, fuzzing, CTF, pesquisa de segurança e geração de payloads mínimos. Para time de plataforma, a lição é sobre verificação automática, não sobre magia do modelo. O que funciona é o par modelo mais teste executável, e isso você pode copiar hoje para outras tarefas frágeis, geração de regex complexa, migração de config, patch pequeno em infraestrutura como código. Quem perde, pelo menos por enquanto, é a ideia de build reprodutível e auditável. O mesmo spec pode sair em uma tentativa ou em seis, de forma não determinística, e programas ainda são minúsculos. Ninguém vai gerar um browser de 439 bytes.
Se você quer tirar algo útil disso ainda hoje, faça o óbvio e barato. Monte um harness parecido para o seu caso, nem que seja em 50 linhas, onde o LLM propõe um artefato e um teste real valida, seja teste unitário, seja container efêmero, seja verificação de binário com readelf ou objdump. Uma ação prática imediata é criar um sandbox descartável para rodar saída de modelo que mexe com sistema, porque aqui o aviso é sério, são binários gerados por modelo sendo executados de verdade. Não rode isso na sua máquina principal sem ler o script antes. Use VM, container sem privilégio, sem rede, com limite de CPU e memória. E registre cada tentativa, prompt, hex retornado, tamanho, saída do readelf e exit code, porque esse log vira seu dataset de correção.
- Replique o padrão spec mais execução mais erro cru de volta para o modelo no seu pipeline de código.
- Exija validador determinístico antes de aceitar qualquer artefato, teste, screenshot, checksum ou análise de binário.
- Isole a execução em ambiente descartável e versione os logs para entender onde o modelo costuma quebrar.
Isso escala ou só impressiona
Aqui entra a tensão real. Isso prova raciocínio de baixo nível impressionante, o modelo internalizou ELF, syscalls Linux, ABI x86-64 e protocolo X a ponto de cuspir bytes que o kernel aceita. Mas prova junto que o modelo sozinho não se sustenta, sem o loop de correção ele morre no primeiro segfault. Então resolve ou só move o gargalo. Move o gargalo da escrita para a verificação. Você não precisa mais escrever os 47 bytes na mão, mas precisa escrever o teste que diz se aqueles 47 bytes estão certos, e teste bom dá trabalho. Para hello world e servidor mínimo, o teste é trivial, curl respondeu ou não. Para sistema real, com estado, concorrência e segurança, o teste é quase tão complexo quanto o programa.
Tem também a questão de custo e portabilidade. Os resultados são dependentes de modelo, tudo acima é Claude Sonnet 5.5 em x86-64, enquanto os testes em AArch64 usaram outro modelo e não são comparáveis. Em produção, isso significa lock-in comportamental, o que passa em um modelo quebra em outro, e pequenas mudanças de header quebram tudo de forma silenciosa. E a observabilidade é péssima, um dígito hex a mais vira segfault genérico. O loop só funcionou quando passou a devolver estado decodificado, não só sinal de falha. Isso sugere que o futuro não é prompt mágico, e sim harness rico em semântica, com ferramentas que traduzem falha binária em dica acionável. Sem isso, a taxa de acerto no nível byte a byte continua lotérica.
Conclusão
No fim, o recado é simples e incômodo, dá para compilar com linguagem natural se você tiver um verificador implacável do outro lado. O compilador clássico não morreu, ele só ganhou um concorrente probabilístico, barato de prototipar e caro de confiar. Vale testar esse loop no seu contexto, mas com sandbox e métrica de tentativas na mão. Será que a gente vai aceitar binário que só existe porque passou no teste na quinta tentativa.



Comentários
0 comentáriosNenhum comentário ainda. Seja o primeiro a comentar.