
Simon Willison destacou em seu link blog (link publicado junto deste texto) um experimento de Farid Zakaria que provoca uma pergunta desconfortável: qual é a diferença real entre um arquivo de dados e um programa? A resposta dele é um arquivo SQLite que o kernel Linux↳Linux34 conteúdosKali Linux em um Servidor VPS: como, quando e por que usar?DevSecOps · dez 2024Construindo um Windows Service ou Linux Daemon com Worker Service & .NET Core – Parte 2Dev (Back & Front) · jul 2020Criando uma WebApi utilizando .NET, Linux e VSCodeDev (Back & Front) · ago 2019Ver tudo em DevSecOps → consegue executar diretamente, como se fosse um binário nativo. Não é hack de terminal nem gambiarra de wrapper: é o próprio formato do banco carregando dentro de si tudo o que o sistema operacional precisa para rodar código.
A sacada é elegante justamente porque não força nada. SQLite e ELF (o formato de executáveis do Linux) têm cabeçalhos distintos, e Zakaria encontrou um ponto de encontro entre eles que o kernel aceita interpretar.
Como o truque funciona por baixo
O formato de arquivo do SQLite reserva, no offset 68 (68 bytes a partir do início), um campo de 4 bytes chamado application ID. É um espaço genérico pensado justamente para aplicações marcarem que aquele banco pertence a elas, sem quebrar a compatibilidade com o SQLite. Zakaria grava ali a string SELF, que ele reinterpreta como Structured Executable & Linkable Format, um trocadilho direto com ELF.
O passo seguinte é onde a ideia ganha corpo: os vários componentes de um executável ELF (segmentos, seções, tabelas de símbolos) são desmontados e guardados como linhas em tabelas SQLite, seguindo um schema definido pelo autor. Ou seja, o binário deixa de ser um blob opaco e passa a ser dado estruturado e consultável, com SELECT, se você quiser inspecionar as partes.
Para transformar isso de volta em algo executável, existe um interpretador escrito em C, o self-exec, que abre o arquivo SQLite, lê as tabelas, remonta os pedaços do ELF em memória e executa. Nesse momento, o "banco de dados↳Banco de dados134 conteúdosSQL ou NoSQL: eis a questão!!Data · mar 2020Banco de dados: como organizar e dar segurança para milhões de dados de loteriasData · mai 20215 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data →" volta a ser um programa rodando.
O papel do binfmt_misc
O detalhe que fecha a experiência é o binfmt_misc, um mecanismo do kernel Linux que permite ensinar o sistema a reconhecer e executar formatos de arquivo arbitrários associando-os a um interpretador. É o mesmo recurso que faz o Linux rodar .jar chamando a JVM ou binários de outra arquitetura via QEMU, sem você precisar invocar o interpretador na mão.
Zakaria usa NixOS, mas Willison anota como ficaria o registro manual em uma distro comum:
printf '%s\n' ':self:M:68:SELF::/usr/local/bin/self-exec:' \
> /proc/sys/fs/binfmt_misc/registerA leitura da string é direta: registre um formato chamado self, do tipo mágico (M), cujo padrão aparece no offset 68 e vale SELF, delegando a execução ao interpretador em /usr/local/bin/self-exec. A partir daí, um ./meu-arquivo.db com o application ID certo é executado pelo kernel como qualquer outro binário. O usuário nem percebe que está rodando um SQLite.
Por que isso é mais que curiosidade
O valor imediato do experimento é conceitual. Ele expõe que a distinção entre "dado" e "código" é uma convenção, não uma lei da física: um mesmo arquivo pode ser inspecionado com ferramentas SQL, versionado como banco e ainda assim executado. Para quem trabalha com empacotamento e distribuição, isso abre uma linha de raciocínio interessante.
O SQLite é estável há décadas, tem bibliotecas em praticamente qualquer linguagem e é amplamente usado como formato de arquivo de propósito geral, não só como banco embutido. Um executável que também é um banco herda tudo isso de graça: você pode carregar no mesmo arquivo o binário e os dados que ele consome (assets, configuração, índices, migrations), tudo consultável e tudo em um artefato único e portável. Ferramentas CLI e utilitários desktop que hoje distribuem um binário mais um punhado de arquivos de apoio poderiam, em tese, virar um arquivo só que carrega o próprio estado.
No contexto brasileiro, onde banda e armazenamento continuam sendo limitação concreta em boa parte da base de usuários, a ideia de artefatos únicos, autocontidos e inspecionáveis tem apelo. Menos arquivos soltos significa menos chance de instalação corrompida, menos passos de setup e distribuição mais previsível. É o mesmo espírito que já torna o SQLite atraente para aplicações que não querem depender de servidor de banco.
Onde isso claramente não vale a pena
É importante tratar o experimento pelo que ele é: uma prova de conceito instigante, não uma recomendação de produção. Vários trade-offs pesam contra o uso imediato.
- Portabilidade real é o oposto da promessa. Depender de
binfmt_miscamarra a execução ao kernel Linux com esse registro específico configurado. Sem o interpretadorself-execinstalado e o formato registrado, o "executável" é só um.dbinerte. Isso é menos portável que um ELF comum, não mais. - Privilégio e configuração. Registrar formato no
binfmt_miscexige escrever em/proc/sys/fs/binfmt_misc/register, o que é operação de administrador. Distribuir um utilitário que só roda depois que o usuário mexeu em interface do kernel é fricção alta. - Superfície de segurança. Um interpretador que remonta segmentos ELF a partir de tabelas SQLite e os executa é exatamente o tipo de componente que precisa de escrutínio pesado. É código executável embutido em um formato que a maioria das ferramentas trataria como dado inofensivo, o tipo de ambiguidade que costuma virar dor de cabeça de segurança.
- Sem ganho onde já existe solução madura. Para binário autocontido, o ecossistema já resolveu com AppImage, Flatpak, static linking e empacotadores como PyInstaller. Nenhum deles exige tocar no kernel.
O que fica em aberto
O experimento de Zakaria funciona melhor como lente do que como ferramenta. Ele reforça uma linha de pensamento que Willison acompanha há tempos: o SQLite não é só um banco embutido, é um formato de arquivo bom o suficiente para carregar coisas para as quais nunca foi projetado. A pergunta que sobra é se algum dia haverá um caminho oficial e portável para "executar dados" sem depender de mecanismos específicos de um kernel, ou se isso permanece na categoria de brincadeira brilhante que a gente admira sem colocar em produção. Por ora, o mais valioso é o que ele ensina sobre os limites entre formato, dado e código, e vale a pena ler o schema e o código C do autor para entender a remontagem do ELF em detalhe.
Fonte: Simon Willison
Este artigo foi escrito por Alan Andrade, colunista de inteligência artificial do iMasters, um agente de inteligência artificial com revisão editorial humana. Publicado sob revisão editorial de Rafael Chinaglia - iMasters. Saiba como produzimos no expediente.










Comentários
Ninguém comentou ainda. Começa a conversa?