3.12. Formatos de binários

Para entender o motivo pelo qual o FreeBSD usa o formato ELF você deve saber primeiro um pouco mais sobre os três formados atualmente ``dominantes'' de arquivos executáveis UNIX®:

FreeBSD vem do campo ``clássico'' e durate muito tempo usou o formato a.out(5), uma tecnologia utilizada e aprovada por muitos gerações de versões de sistemas BSD, até o ramo 3.X do FreeBSD. Apesar de ser possível gerar binários (e mesmo o kernel) no formato ELF bem antes do FreeBSD 3.X, o sistema inicialmente resistiu à ``pressão'' de mudar para o formato ELF como formato padrão. Por quê? Bem, quando o pessoal do campo Linux fez sua dolorosa transição para ELF, os executáveis a.out não podiam ser utilizados pois sua tabela de salto era consideradavelmente inflexível, e a construção de bibliotecas compartilhadas parecia ser complexa demais no novo formato, para os fabricantes e desenvolvedores em geral. Depois que algumas ferramentas ELF ofereceram soluções ao problema de bibliotecas compartilhadas, o formato passou a ser visto como ``o caminho a ser seguido'', os custos de migração para este formato já eram então aceitáveis, e a transição foi feita. O mecanismo de bibliotecas compartilhadas do FreeBSD é baseado com maior proximidade ao estilo de bibliotecas compartilhadas do SunOS™ da Sun, e como tal, é muito fácil de ser utilizado.

Então, por que existem tantos formatos distintos?

De volta ao sombrio, gélido e distante passado, existiam apenas equipamentos simples de computação. Estes equipamentos simples, suportavam sistemas simples e pequenos. O formato a.out era completamente adequado às tarefas apresentadas pelos binários nestes sistemas simplistas (como PDP-11). Conforme o UNIX passou a ser convertido com base nestes sistemas simples, mantiveram o formado a.out pois era suficiente para as primeiras conversões do UNIX, para arquiteturas como Motorola 68k, VAXen, etc.

Depois algum engenheiro de hardware iluminado decidiu que ele poderia forçar os programas a realizarem algumas tarefas mais simples, de forma que ele poderia retirar alguns ítens de seu projeto de equipamento e permitir que o núcleo de sua CPU processasse de forma mais rápida. Mesmo tendo sido projetado para funcionar com este novo tipo de hardware (conhecido hoje em dia como RISC), o formato a.out não se encaixava funcionalmente para o novo equipamento, então vários formatos foram desenvolvidos para tentar garantir melhor performance deste novo equipamento, quando comparado ao que o limitado formato a.out poderia oferecer. Algumas coisas como COFF, ECOFF, e alguns outros formatos obscuros foram inventados e suas limitaçòes exploradas antes que as coisas pudessem se estabilizar no formato ELF.

Em adição, o tamanho dos programas estavam se tornando grandes, e os discos (bem como memória física) continuavam relativamente pequenos, então o conceito de bibliotecas compartilhadas nasceu. O sistema de memória virtual também se tornou mais sofisticado. Enquanto cada um desses avanços foram feitos utilizando o formato a.out, sua usabilidade foi se tornando cada vez mais duvidosa, na proporção que novas características eram adicionadas. Em adição, as pessoas queriam poder carregar as coisas de forma dinâmica, no momento de execussão do sistema, ou então dispensar trechos de seus programas depois que o código inicial tivesse sido executado, para economizar memória e espaço de troca (swap) As linguagens se tornaram mais sofisticadas, e as pessoas queriam que códigos fossem carregados antes do programa principal de forma automática. Uma série de modificações foram feitas no formato a.out para permitir que esse tipo de coisa pudesse acontecer, e basicamente tudo funcionou bem por um tempo. Em determinado momento, o a.out não podia mais contornar estes problemas sem sobrecarregar seu código e aumentar sua complexidade. O formato ELF resolvia a maioria desses problemas, mas seria doloroso migrar de um sistema que, basicamente, funcionava. Então o formato ELF teve que esperar até que fosse mais penoso continuar com o a.out, do que migrar para o ELF.

Contudo, com o passar do tempo, as ferramentas de construção de onde o FreeBSD derivou suas próprias ferramentas de construção (o montador assembly e o carregador, especialmente) se envolveram em duas árvores paralelas. A árvore FreeBSD adicionou bibliotecas compartilhadas e corrigiu algumas falhas. O pessoal GNU que originalmente escreviam esses programas, rescreveram os mesmos de adicionaram suporte simples à compilação cruzada, podendo adicionar formatos diferentes à bel prazer, e assim por diante. Partindo do princípio que muitas pessoas desejavam criar compiladores cruzados para o FreeBSD, tiveram problemas pois os fontes antigos do FreeBSD faziam chamadas ao as e ld o que não possibilitava tal tarefa. A nova corrente de ferramentas GNU (binutils) suporta compilação cruzada, ELF, bibliotecas compartilhadas, extensões C++, etc. Além disso, muitos fabricantes passaram a lançar binários ELF, e era bom que o FreeBSD pudesse rodá-los.

ELF é mais expressivo que a.out e oferece mais extensibilidade no sistema base. As ferramentas ELF são melhor mantidas, e oferecem suporte à compilação cruzada, que é importante para muita gente. O formato ELF pode ser um pouco mais lento do que a.out, mas tentar medir esta diferença é bem difícil. Existem ainda vários detalhes distintos entre ambos, em relação à como eles mapeiam páginas, tratam código de inicialização, carregamento das instruções, etc. Nenhum destes fatores são muito relevantes, mas são diferentes. Futuramente, o suporte à a.out será retirado do kernel GENERIC, e eventualmente removido do sistema quando a necessidade de executar programas a.out for passado.

Este, e outros documentos, podem ser obtidos em ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Para perguntas sobre FreeBSD, leia a documentação antes de contatar <questions@FreeBSD.org>.
Para perguntas sobre esta documentação, envie e-mail para <doc@FreeBSD.org>.