---
title: Capítulo 10. Compatibilidade binária com o Linux®
part: Parte II. Tarefas comuns
prev: books/handbook/printing
next: books/handbook/partiii
---

[[linuxemu]]
= Compatibilidade binária com o Linux(R)
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:source-highlighter: rouge
:experimental:
:skip-front-matter:
:toc-title: Índice
:table-caption: Tabela
:figure-caption: Figura
:example-caption: Exemplo
:xrefstyle: basic
:relfileprefix: ../
:outfilesuffix:
:sectnumoffset: 10

ifeval::["{backend}" == "html5"]
:imagesdir: ../../../images/books/handbook/linuxemu/
endif::[]

ifeval::["{backend}" == "pdf"]
:imagesdir: ../../../../static/images/books/handbook/linuxemu/
endif::[]

ifeval::["{backend}" == "epub3"]
:imagesdir: ../../../../static/images/books/handbook/linuxemu/
endif::[]

include::shared/authors.adoc[]
include::shared/releases.adoc[]
include::shared/pt-br/mailing-lists.adoc[]
include::shared/pt-br/teams.adoc[]
include::shared/pt-br/urls.adoc[]

toc::[]

[[linuxemu-synopsis]]
== Sinopse

O FreeBSD fornece compatibilidade binária com o Linux(TM), permitindo que os usuários instalem e executem a maioria dos binários do Linux(TM) em um sistema FreeBSD sem ter que primeiro modificar o binário. Foi até relatado que, em algumas situações, os binários Linux(TM) têm melhor desempenho no FreeBSD do que no Linux(TM).

No entanto, alguns recursos do sistema operacional específicos do Linux(TM) não são suportados no FreeBSD. Por exemplo, os binários Linux(TM) não funcionarão no FreeBSD se usarem chamadas específicas i386(TM), mesmo ativando o modo 8086 virtual.

[NOTE]
====
O suporte para compatibilidade binária de 64 bits com o Linux(TM) foi adicionado no FreeBSD 10.3.
====

Depois de ler este capítulo, você saberá:

* Como habilitar a compatibilidade binária com o Linux(TM) em um sistema FreeBSD.
* Como instalar bibliotecas compartilhadas adicionais do Linux(TM).
* Como instalar aplicativos Linux(TM) em um sistema FreeBSD.
* Os detalhes de implementação da compatibilidade com o Linux(TM) no FreeBSD.

Antes de ler este capítulo, você deve:

* Saiber como instalar crossref:ports[ports,software adicional de terceiros].

[[linuxemu-lbc-install]]
== Configurando a compatibilidade binária com o Linux(TM)

Por padrão, as bibliotecas do Linux(TM) não estão instaladas e a compatibilidade binária com o Linux(TM) não está ativada. As bibliotecas Linux(TM) podem ser instaladas manualmente ou a partir da coleção de Ports do FreeBSD.

Antes de tentar compilar o port, carregue o módulo de kernel Linux(TM), caso contrário a compilação irá falhar:

[source,shell]
....
# kldload linux
....

Para compatibilidade com 64 bits:

[source,shell]
....
# kldload linux64
....

Para verificar se o módulo está carregado:

[source,shell]
....
% kldstat
      Id Refs Address    Size     Name
      1    2 0xc0100000 16bdb8   kernel
      7    1 0xc24db000 d000     linux.ko
....

O pacote ou port package:emulators/linux_base-c7[] é a maneira mais fácil de instalar um conjunto básico de bibliotecas e binários do Linux(TM) em um sistema FreeBSD. Para instalar o port:

[source,shell]
....
# pkg install emulators/linux_base-c7
....

Para que a compatibilidade com o Linux(TM) seja ativada durante a inicialização, adicione esta linha ao [.filename]#/etc/rc.conf#:

[.programlisting]
....
linux_enable="YES"
....

Em máquinas de 64 bits, o [.filename]#/etc/rc.d/abi# carregará automaticamente o módulo para emulação de 64 bits.

Como a camada de compatibilidade binária do Linux(TM) ganhou suporte para a execução de binários Linux(TM) de 32 e 64 bits (em hosts x86 de 64 bits), não é mais possível vincular estaticamente a funcionalidade de emulação a um kernel personalizado.

[[linuxemu-libs-manually]]
=== Instalando Bibliotecas Adicionais Manualmente

Se um aplicativo Linux(TM) reclamar sobre a falta de bibliotecas compartilhadas após configurar a compatibilidade binária do Linux(TM), determine quais bibliotecas compartilhadas o Linux(TM) precisa e instale-as manualmente.

A partir de um sistema Linux(TM), o `ldd` pode ser usado para determinar quais bibliotecas compartilhadas o aplicativo precisa. Por exemplo, para verificar quais bibliotecas compartilhadas o `linuxdoom` precisa, execute este comando a partir de um sistema Linux(TM) que tenha o Doom instalado:

[source,shell]
....
% ldd linuxdoom
libXt.so.3 (DLL Jump 3.1) => /usr/X11/lib/libXt.so.3.1.0
libX11.so.3 (DLL Jump 3.1) => /usr/X11/lib/libX11.so.3.1.0
libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29
....

Então, copie todos os arquivos listados na última coluna da saída do comando no sistema Linux(TM) para o diretório [.filename]#/compat/linux# no sistema FreeBSD. Depois de copiados, crie links simbólicos para os nomes na primeira coluna. Este exemplo irá resultar nos seguintes arquivos no sistema FreeBSD:

[source,shell]
....
/compat/linux/usr/X11/lib/libXt.so.3.1.0
/compat/linux/usr/X11/lib/libXt.so.3 -> libXt.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3 -> libX11.so.3.1.0
/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29
....

Se uma biblioteca compartilhada Linux(TM) já existir com um número de revisão principal correspondente à primeira coluna da saída do comando `ldd`, ela não precisará ser copiada para a arquivo nomeado na última coluna, pois a biblioteca existente deve funcionar. No entanto é aconselhável copiar a biblioteca compartilhada se for uma versão mais nova. O arquivo antigo pode ser removido, desde que o link simbólico aponte para o novo.

Por exemplo, essas bibliotecas já existem no sistema FreeBSD:

[source,shell]
....
/compat/linux/lib/libc.so.4.6.27
/compat/linux/lib/libc.so.4 -> libc.so.4.6.27
....

e o `ldd` indica que um binário requer uma versão posterior:

[source,shell]
....
libc.so.4 (DLL Jump 4.5pl26) -> libc.so.4.6.29
....

Como a biblioteca existente tem apenas uma ou duas versões desatualizadas no último dígito, o programa ainda deve funcionar com a versão um pouco mais antiga. No entanto, é seguro substituir o [.filename]#libc.so# existente pela versão mais nova:

[source,shell]
....
/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29
....

Geralmente, será necessário procurar as bibliotecas compartilhadas que os binários do Linux(TM) dependem apenas das primeiras vezes que um programa Linux(TM) é instalado no FreeBSD. Depois de um tempo, haverá um conjunto suficiente de bibliotecas Linux(TM) compartilhadas no sistema para poder executar binários Linux(TM) atualizados sem qualquer trabalho extra.

=== Instalando os binários Linux(TM)ELF

Os binários ELF requerem por vezes um passo extra. Quando um binário ELF sem marca for executado, ele gerará uma mensagem de erro:

[source,shell]
....
% ./my-linux-elf-binary
ELF binary type not known
Abort
....

Para ajudar o kernel do FreeBSD a distinguir entre um binário do FreeBSD ELF e um binário Linux(TM), use man:brandelf[1]:

[source,shell]
....
% brandelf -t Linux my-linux-elf-binary
....

Como o conjunto de ferramentas GNU coloca as informações de branding apropriadas em binários ELF automaticamente, essa etapa geralmente não é necessária.

=== Instalando um aplicativo baseado em Linux(TM)RPM

Para instalar um aplicativo baseado em Linux(TM)RPM, primeiro instale o pacote ou o port package:archivers/rpm4[]. Uma vez instalado, o usuário `root` pode usar este comando para instalar um [.filename]#.rpm#:

[source,shell]
....
# cd /compat/linux
# rpm2cpio < /path/to/linux.archive.rpm | cpio -id
....

Se necessário, use o `brandelf` nos binários ELF instalados . Observe que isso impedirá uma desinstalação limpa.

=== Configurando o Resolver do Hostname

Se o DNS não funcionar ou este erro aparecer:

[source,shell]
....
resolv+: "bind" is an invalid keyword resolv+:
"hosts" is an invalid keyword
....

configure o [.filename]#/compat/linux/etc/host.conf# como segue:

[.programlisting]
....
order hosts, bind
multi on
....

Isso especifica que o [.filename]#/etc/hosts# deve ser pesquisado primeiro e o DNS deve ser pesquisado em segundo lugar. Quando o [.filename]#/compat/linux/etc/host.conf# não existe, os aplicativos Linux(TM) usam o [.filename]#/etc/host.conf# e avisam sobre a sintaxe incompatível do FreeBSD. Remova o `bind` se um servidor de nomes não estiver configurado usando o [.filename]#/etc/resolv.conf#.

[[linuxemu-advanced]]
== Tópicos Avançados

Esta seção descreve como funciona a compatibilidade binária com o Linux(TM) e é baseada em um email escrito para http://lists.FreeBSD.org/mailman/listinfo/freebsd-chat[Lista de discussão do chat do FreeBSD] por Terry Lambert mailto:tlambert@primenet.com[tlambert@primenet.com] (Message ID: `<199906020108.SAA07001@usr09.primenet.com>`).

O FreeBSD tem uma abstração chamada "loader de classes de execução". Esta é uma cunha na chamada de sistema man:execve[2] .

Historicamente, o loader UNIX(TM) examinava o número mágico (geralmente os primeiros 4 ou 8 bytes do arquivo) para ver se era um binário conhecido pelo sistema e, em caso afirmativo, invocava o loader binário.

Se o arquivo não fosse o tipo binário adequado para o sistema, a chamada man:execve[2] retornava uma falha, e o shell tentava iniciar a execução do mesmo como um comando do shell. A suposição era um padrão de "qualquer que seja o shell atual".

Posteriormente, foi feito um hack para que o man:sh[1] examinasse os dois primeiros caracteres e se eles fossem `:\n`, ele invocava o shell man:csh[1] em seu lugar.

O FreeBSD tem uma lista de loaders, em vez de um único loader, com um fallback para o loader `#!` para executar interpretadores de shell ou scripts de shell.

Para o suporte ao Linux(TM)ABI, o FreeBSD vê o número mágico como um binário ELF. O loader ELF procura por uma _marca_ especializada, que é uma seção de comentários na imagem ELF e que não esteja presente nos binários ELF SVR4/Solaris(TM).

Para que os binários Linux(TM) funcionem, eles devem ser _marcados_ como tipo `Linux` usando o comando man:brandelf[1]:

[source,shell]
....
# brandelf -t Linux file
....

Quando o loader ELF vê a marca `Linux`, ele substitui um ponteiro na estrutura `proc`. Todas as chamadas do sistema são indexadas por esse ponteiro. Além disso, o processo é sinalizado para manipulação especial do vetor trap para o código de trampolim de sinal, e vários outros (menores) reparos que são manipulados pelo módulo do kernel Linux(TM).

O vetor de chamada do sistema Linux(TM) contém, entre outras coisas, uma lista de entradas `sysent[]` cujos endereços residem no módulo do kernel.

Quando uma chamada de sistema é acionada pelo binário Linux(TM), o código de interceptação desreferencia o ponteiro de função de chamada do sistema da estrutura `proc` e obtém a classe Linux(TM), não a FreeBSD, como ponto de entrada para a chamada do sistema.

O modo Linux(TM) procura fazer _reroots_ dinamicamente. Isso é, na verdade, equivalente ao `union` para montagens de sistema de arquivos. Primeiro, é feita uma tentativa de procurar o arquivo em [.filename]#/compat/linux/original-path#. Se isso falhar, a pesquisa será feita em [.filename]#/original-path#. Isso garante que os binários que exigem outros binários possam ser executados. Por exemplo, o conjunto de ferramentas Linux(TM) pode ser executado sob o suporte da Linux(TM)ABI. Isso também significa que os binários Linux(TM) podem carregar e executar binários do FreeBSD, se não houver binários Linux(TM) correspondentes, e que o comando man:uname[1] pode ser colocado na árvore de diretórios [.filename]#/compat/linux# para garantir que os binários Linux(TM) não possam dizer que não estão rodando em Linux(TM).

De fato, existe um kernel Linux(TM) no kernel do FreeBSD. As várias funções subjacentes que implementam todos os serviços fornecidos pelo kernel são idênticas às entradas da tabela de chamada do sistema FreeBSD, e às entradas da tabela de chamada do sistema Linux(TM): operações do sistema de arquivos, operações de memória virtual, entrega de sinal e System V IPC. A única diferença é que os binários do FreeBSD obtêm as funções de _cola_ do FreeBSD, e os binários Linux(TM) recebem as funções de _cola_ do Linux(TM). As funções de _cola_ do FreeBSD estão estaticamente ligadas ao kernel, e as funções de _cola_ do  Linux (TM) podem ser estaticamente ligadas, ou podem ser acessadas através de um módulo do kernel.

Tecnicamente, isso não é realmente emulação, é uma implementação de ABI. Às vezes é chamado de "emulação(TM) Linux " porque a implementação foi feita num momento em que não havia outra palavra para descrever o que estava acontecendo. Dizer que o FreeBSD executava os binários do Linux(TM) não era verdade, já que o código não era compilado nele.
