22.8. Tópicos Anvaçados

Se você está curioso para saber como a compatibilidade binária Linux funciona, esta é a seção que você quer ler. Muito do que se segue é pesadamente baseado em um mensagem de correio escrita para lista de discussão FreeBSD bate papo (chat) por Terry Lambert (Message ID: <199906020108.SAA07001@usr09.primenet.com>).

22.8.1. Como Funciona?

O FreeBSD possui uma abstração chamada ``execution class loader''. Isto é uma espécie de cunha na chamada de sistema execve(2).

Acontece que o FreeBSD possui uma lista de carregadores, ao invés de apenas um carregador que volta para o carregador #! para executar qualquer interpretador de linha de comando ou shell scripts.

Historicamente, o único carregador na plataforma UNIX® que examinou o número mágico (geralmente os primeiros 4 ou 8 bytes do arquivo) para ver se era um binário conhecido do sistema, e se fosse, invocaria o carregador do binário.

Se não fosse o tipo de binário para o sistema, o execve(2) retornaria uma falha, e o shell tentaria executá-lo como um comando.

Assumiasse que o padrão era ``qualquer que fosse o shell''.

Mais tarde, um ajuste foi feito no sh(1) para examinar os dois primeiros caracteres, e se eles fossem :\n, então o shell csh(1) seria invocado (acreditamos a SCO foi a primeira a fazer este ajuste).

O que o FreeBSD faz agora é ir à uma lista de carregadores, com um carregador #! genérico que sabe a respeito dos interpretadores como os caracteres que seguem o próximo espaço em branco próximo aoúltimo caracter, seguidos de um retorno para /bin/sh.

Para o suporte ABI pra Linux, o FreeBSD vê o número mágico como um binário ELF (não faz distinção entre FreeBSD, Solaris™, Linux ou qualquer outro SO que possui um tipo de imagem ELF, neste momento).

O carregador ELF procura por uma marca especializada, que é uma seção de comentário na imagem ELF, que não está presente nos binários ELF do SVR4/Solaris.

Para que os binários Linux funcionem, eles devem estar marcados como tipo Linux de brandelf(1):

# brandelf -t Linux file

Quando isto estiver feito, o carregador ELF verá a marca Linux no arquivo.

Quando o carregador ELF vê uma marca Linux, ele substiui um ponteiro na estrutura do proc. Todas as chamadas de sistema indexadas através deste ponteiro (em um sistema UNIX tradicional, que pode ser a estrutura de array sysent[], contendo as chamadas de sistema). Adicionalmente, o processo é marcado para uma manipulação especial do vetor para um código de sinal trampolim, e uma série de outros (pequenos) ajustes que são manipulados pelo módulo kernel do Linux.

O vetor de chamada Linux contém, entre outras coisas, uma lista de entradas sysent[] as quais seus endereços residem no módulo de kernel.

Quando uma chamada de sistema é feita por um binário Linux, o código de armadilha diferencia o ponteiro da função de chamada de sistema como estando fora da estrutura proc, e pega os pontos de entrada de chamada de sistema Linux, e não FreeBSD.

Além disso, o modo Linux dinamicamente redireciona as procuras; que é, na verdade, o que a opção union faz para as montagens de sistema de arquivo (não o tipo de sistema de arquivo unionfs!). Primeiro, uma tentativa é feita no diretório /compat/linux/original-path, então se falhar, a procura é feita no diretório /original-path. Isto certifica que os binários que requerem outros binários possam ser executados (e.g., o toolchain Linux pode rodar sob o suporte ABI Linux). Isto também significa que os binários Linux pode carregar e executar binários FreeBSD, se não binários Linux correspondentes presentes, e que e que você possa colocar um comando uname(1) na árvore do diretório /compat/linux para ter certeza de que os binários Linux não possam dizer que eles não estão rodando no Linux.

Efetivamente, existe um kernel Linux dentro no kernel do FreeBSD; as mais variadas funcções internas que implementam todos os serviços oferecidos pelo kernel são idênticos de ambas as entradas das tabelas de chamadas de sistema do FreeBSD, e as entradas das tabelas de chamada do Linux: operações de sistema de arquivo, operações de memória virtual, entrega de sinais, IPC do SystemV, etc... A única diferença é que os binários do FreeBSD obtém funções ``cola'' FreeBSD e binários Linux obtém funções ``cola'' Linux (SO's muito mais antigos possuem suas próprias funções ``cola'': endereçamento de funções em uma estrutura array sysent[] estática global, ao invés de endereçamento de funções não referenciadas de um ponteiro dinamicamente incializado na estrutura proc da realização da chamada do processo).

Qual é a ABI nativa do FreeBSD? Não importa. Basicamente a única diferença é que (atualmente; isso pode ser facilmente modificado em uma versão futura, e e provavelmente será depois disso) as funções ``cola'' FreeBSD são estaticamente ligadas no kernel, e as funções ``cola'' do Linux podem ser estaticamente ligadas, ou podem ser acessadas através de um módulo de kernel.

Sim, mas isso realmente é emulação? Não. É uma implementação ABI. Não existe emulador envolvido (ou simulador, para cortar a próxima questão).

Então por que é chamado de ``emulação Linux''? Para fazer com que seja difícil vender o FreeBSD! Verdade, é porque a implementação histórica foi feita numa época quando não havia outra palavra além desta para descrever o que estava acontecendo; dizer que o FreeBSD executava binários Linux não era verdade, se você não compilou o código ou carregou o módulo, então existia uma expressão para descrever o que estava sendo executado-- ``o emulador Linux''.

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>.