O SQLite como formato executável: projeto SELF troca o ELF por um banco de dados
Farid Zakaria publicou um protótipo que substitui o formato ELF por um arquivo SQLite que você dá chmod +x e roda. strip vira DELETE, ldd vira JOIN e o sistema inteiro cabe num único .db.

Um arquivo que o file identifica como SQLite 3.x database e que, mesmo assim, roda quando você faz ./hello. É isso que o engenheiro Farid Zakaria demonstra em "Your executable is a SQLite database", publicado em agosto e discutido no Hacker News. O projeto se chama SELF (Structured Executable & Linkable Format) e propõe substituir o ELF, o formato binário padrão do 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 →, por um 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 → SQLite.
A ideia não é nova para o autor: ela vem da tese de doutorado dele e de uma ferramenta anterior, o sqlelf, que já permitia consultar arquivos ELF via SQL (SELECT name FROM elf_symbols em vez de combinar readelf com grep). A diferença agora é radical: não é um banco que descreve o executável, é o próprio arquivo que você torna executável e roda.
$ file hello
hello: SQLite 3.x database, application id 0x53454c46, user version 1
$ ./hello
Hello, world!
$ sqlite3 hello 'SELECT soname FROM ldd'
libc.so.6A tese: o ELF já é um banco de dados mal disfarçado
O argumento central de Zakaria é que o ELF reinventa, à mão, primitivas que qualquer banco de dados já oferece. A tabela que ele monta no post é a parte mais provocativa do texto:
.strtab/.dynstrfazem string interning.hash/.gnu.hashsão um índice (umCREATE INDEX)- a section header table é o
sqlite_schema, uma tabela de tabelas st_name → offseté uma foreign key feita na unhaobjcopy --strip-debugé umDELETEseguido deVACUUM
O ELF foi projetado para um mundo em que disco e banda eram caríssimos: é um formato extremamente compacto, difícil de modificar (muitas vezes você precisa zerar seções e recriar outras porque tudo está empacotado justo) e sem schema autodescritivo. O SQLite é o contraexemplo: formato estável, autodescritivo, projetado para ser estendido sem quebrar consumidores existentes.
O que desaparece quando você troca o formato
Um arquivo SELF precisa de apenas duas tabelas para rodar: self_meta (o cabeçalho ELF como pares chave/valor) e segments (a imagem de carga, uma linha por program header, com os bytes num BLOB). A tabela de símbolos substitui várias seções ELF de uma vez:
CREATE TABLE symbols (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
version TEXT,
value INTEGER, size INTEGER,
type TEXT, bind TEXT,
defined INTEGER NOT NULL,
exported INTEGER NOT NULL
);
CREATE INDEX idx_symbols_name ON symbols (name, version);Com isso, o .dynstr some (o name é TEXT e o SQLite já faz interning de strings), o versionamento de símbolos vira uma coluna em vez do arranjo .gnu.version_r/.gnu.version_d, e o índice é uma b-tree mantida pelo SQLite no lugar do bloom filter feito à mão do .gnu.hash.
A consequência prática é que toda ferramenta que lê ELF vira uma query, e toda ferramenta que modifica ELF vira uma transação. Onde antes havia cirurgia frágil de offsets, agora há SQL:
# strip(1) vira DELETE + VACUUM
$ sqlite3 hello 'DELETE FROM sections; DELETE FROM notes; VACUUM;'
# 57344 -> 49152 bytes, e ainda roda
$ ./hello
Hello, world!Nas palavras do autor, strip é um DELETE, patchelf é um UPDATE e ldd é uma view (um join da tabela de símbolos com os segmentos). Informação que faltar no schema pode ser exposta como uma VIEW.
Como o kernel roda um arquivo SQLite
O truque está no application_id, um campo de 4 bytes que o SQLite reserva no offset 68 do cabeçalho justamente para esse tipo de uso. O SELF carimba ali a assinatura SELF, de modo que um banco SQLite comum nunca é confundido com um executável.
O restante é o binfmt_misc, o subsistema do Linux que permite invocar qualquer arquivo como se fosse binário nativo, registrando uma magic e um interpretador. No NixOS, a configuração são poucas linhas casando a magic do SQLite no offset 0 e SELF no offset 68. O interpretador é o self-exec, um pequeno programa em C linkado contra libsqlite3 cujo funcionamento lembra o do ld.so: busca program headers e símbolos no banco, mapeia os segmentos na memória, faz as relocações e salta para o entry point. (O self-exec precisa continuar sendo um ELF, senão o kernel entra em recursão até dar -ELOOP.)
Para linkagem dinâmica, Zakaria testou dois caminhos: usar a interface rtld-audit da glibc para responder "qual biblioteca satisfaz esse símbolo?" com uma query SQL, mantendo lazy PLT, IFUNCs, TLS e versionamento de símbolos funcionando; e um linker dinâmico próprio escrito inteiramente em SQL, o self-ld, ainda como prova de conceito.
O preço: dobro do tamanho e mmap perdido
Aqui entram os números que impedem que isso seja levado a produção hoje. Um arquivo SELF carrega o overhead da b-tree do SQLite e fica cerca de duas vezes maior que o ELF equivalente. Grande parte é recuperável com strip: um coreutils SELF stripado ficou em 1.794.048 bytes contra 1.768.632 do ELF, diferença abaixo de 1%.
O problema mais sério é a latência. Há um custo fixo de aproximadamente 5 ms para abrir o SQLite e iniciar o interpretador, mais uma cópia proporcional ao tamanho da imagem. E essa cópia é pior do que parece: como os bytes vêm das páginas da b-tree em vez de serem mapeados, dois processos rodando o mesmo binário SELF não compartilham páginas de texto como fariam com um ELF normalmente carregado via mmap. Perde-se uma das grandes vantagens do modelo tradicional de carregamento.
O lado surpreendente: um userland inteiro num arquivo
A parte mais interessante do experimento é o conceito de closure. Como o ldd só lista sonames (é ambíguo sobre qual arquivo específico satisfaz cada dependência), o SELF armazena o caminho resolvido de cada aresta no banco, transformando resolução de biblioteca em foreign key e ldd em JOIN. O comando self closure empacota um binário e todas as suas dependências transitivas num único .db. O ls mais suas cinco bibliotecas viraram um arquivo de 4,8 MiB.
Levando ao extremo, o autor apontou o self closure para todos os binários do PATH do sistema: 723 executáveis, 400 bibliotecas distintas, 1.123 objetos, 346.386 símbolos e 3.808 arestas de dependência, tudo num único arquivo SQLite. E, por deduplicação, o resultado ficou até menor que a soma dos ELFs: 611,9 MiB de banco contra 644,4 MiB de ELF.
O que isso muda (e o que fica em aberto)
É importante separar hype de realidade: SELF é um protótipo de pesquisa, disponível no GitHub, rodando primariamente sobre NixOS via um hook postFixup que converte ELF para SELF por pacote. Não há ainda gcc ou ld emitindo SELF diretamente, o overhead de tamanho é real e a perda de compartilhamento de páginas via mmap é um obstáculo concreto de desempenho para o modelo se generalizar.
Para quem constrói software no Brasil, o valor imediato não está em trocar o toolchain, e sim na provocação: boa parte da dor de mexer com binários (parsers reescritos em todo lugar, cirurgia de offsets, caches de índice fora de banda como o ldconfig e o debuginfod) existe porque o formato não é consultável. Repensar o executável como dados estruturados e consultáveis é uma ideia que dialoga direto com quem trabalha com distribuição reproduzível, análise de dependências e supply chain. Fica em aberto se o custo de runtime pode ser amortizado, se um linker 100% em SQL escala, e se a indústria tem apetite para desafiar a inércia de um formato que domina o Linux há décadas.
Fonte: Hacker News
Este artigo foi escrito por Redação iMasters. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.
EUA ordenam remoção do DeepSeek de órgãos federais por risco de dados
Uma ordem do Departamento de Segurança Interna determina que agências civis dos EUA parem de comprar e removam produtos baseados no DeepSeek, ampliando uma restrição que já valia para sistemas de inteligência.














