stamatios
← Voltar ao feed
Ícone de programa transformado em gaveta de arquivo com fichas, metáfora do formato SELF usando SQLite como executável
Dev & Engenharia

SELF propõe executáveis como bancos SQLite no lugar do ELF

resumo de ~3 min

A proposta

SELF, sigla de Structured Executable & Linkable Format, é um protótipo que transforma o executável em um banco de dados SQLite real: o arquivo pode ser marcado com chmod +x, executado pelo sistema e consultado com SQL. A proposta parte da observação de que o ELF já implementa, manualmente, várias primitivas de banco de dados, como interning de strings, índices, relações entre nomes e offsets e estruturas de registros. O SQLite ofereceria um formato autodescritivo, estável, extensível e consultável, em vez de um formato compacto cujas convenções precisam ser reimplementadas por cada ferramenta.

Estrutura e ferramentas

Um arquivo SELF precisa, para executar, das tabelas self_meta, que representa o cabeçalho ELF como pares de chave e valor, e segments, que armazena a imagem carregável, com os bytes em campos BLOB. A tabela symbols concentra informações que no ELF ficam distribuídas por várias seções, enquanto um índice B-tree do SQLite substitui os índices de símbolos do formato tradicional. Versão, tipo, escopo e estado de definição dos símbolos viram colunas.

Tabelas opcionais, como sections, notes e dynamic_entries, podem ser removidas sem impedir a execução. Assim, operações de leitura passam a ser consultas SQL: ldd pode consultar dependências, nm pode listar símbolos e readelf pode examinar segmentos. Operações de alteração também ganham uma representação transacional: strip equivale a apagar tabelas e executar VACUUM, enquanto patchelf seria uma atualização de registros. Informações não previstas no esquema podem ser expostas por visões, como exports, imports e ldd.

Execução e vinculação dinâmica

A identificação usa o campo application_id de quatro bytes reservado pelo SQLite no offset 68 do cabeçalho, preenchido com a marca SELF. O binfmt_misc reconhece essa combinação e encaminha o arquivo ao interpretador self-exec, um pequeno programa em C ligado à biblioteca libsqlite3. O interpretador lê os cabeçalhos e símbolos no banco, mapeia os segmentos carregáveis, faz as relocações e salta para o ponto de entrada. Ele próprio precisa continuar sendo um ELF para não recair em recursão.

Para vinculação dinâmica, o protótipo testa uma abordagem que mantém o ld.so e intercepta buscas de bibliotecas pela interface glibc rtld-audit, respondendo com consultas SQL. Essa alternativa preserva recursos do glibc, como PLT preguiçoso, IFUNCs, TLS e versionamento de símbolos. Outra implementação experimental, self-ld, realiza a busca e a vinculação inteiramente em SQL; ela mapeia objetos, publica exportações e corrige a tabela global de endereços (GOT), mas ainda é uma prova de conceito.

Custos e escala

Sem remoção de dados opcionais, um SELF fica aproximadamente duas vezes maior que um ELF por causa do custo das árvores B-tree. Depois de despojado, porém, um binário coreutils mediu 1.794.048 bytes, contra 1.768.632 no ELF, diferença inferior a 1%. A execução acrescenta cerca de 5 milissegundos fixos para abrir o SQLite e iniciar o interpretador, além de uma cópia proporcional à imagem. Como as páginas são copiadas para fora das árvores B-tree, processos que executam o mesmo SELF não compartilham páginas de texto como em um ELF mapeado por mmap.

O formato também pode armazenar um closure: o programa e todas as bibliotecas transitivas em um único banco, com cada dependência resolvida por um caminho específico. Em um teste com 723 executáveis, 400 bibliotecas distintas, 1.123 objetos, 346.386 símbolos e 3.808 arestas de dependência, o banco ocupou 611,9 MiB, menos que os 644,4 MiB dos ELFs originais. A deduplicação de bibliotecas e símbolos é feita pelo próprio esquema. Até LD_PRELOAD pode virar uma tabela: ativar, desativar ou reverter uma substituição passa a ser uma transação.

Estado do protótipo

O formato faz conversões sem perda entre ELF e SELF, e as ferramentas já consultam, modificam e empacotam closures. A execução por SQL funciona em programas glibc não modificados, enquanto o carregador nativo é suficiente para explorar a ideia. O projeto inclui uma máquina virtual NixOS cujo executável hello é um banco SQLite, mas o texto apresenta SELF como uma exploração de formato e infraestrutura, não como substituição já adotada pelo ecossistema.