O executável de um programa pequeno e extremamente simples, como o mostrado abaixo, compilado em um sabor do Linux, será executado em um sabor diferente? Ou precisaria ser recompilado?
A arquitetura da máquina é importante em um caso como esse?
int main()
{
return (99);
}
linux
compiling
architecture
compatibility
JCDeen
fonte
fonte
glibc
lá ou vice-versa. Concedido, não é totalmente impossível .gcc -m32 -static
). Ao fazer isso, qualquer Linux i386 ou amd64 poderá executar o executável.Respostas:
Depende. Algo compilado para IA-32 (Intel de 32 bits) pode ser executado no amd64, pois o Linux na Intel mantém a compatibilidade retroativa com aplicativos de 32 bits (com o software adequado instalado). Aqui está o seu
code
compilado no sistema RedHat 7.3 de 32 bits (por volta de 2002, gcc versão 2.96) e o binário copiado para e executado em um sistema Centos 7.4 de 64 bits (por volta de 2017):O RedHat 7.3 antigo para o Centos 7.4 (essencialmente RedHat Enterprise Linux 7.4) permanece na mesma família "distribuição", portanto, provavelmente terá portabilidade melhor do que passar de uma instalação aleatória do "Linux a partir do zero" de 2002 para outra distribuição aleatória do Linux em 2018 .
Algo compilado para amd64 não seria executado apenas em versões de 32 bits do Linux (o hardware antigo não sabe sobre o novo hardware). Isso também é válido para novos softwares compilados em sistemas modernos destinados a serem executados em coisas antigas, já que bibliotecas e até chamadas de sistema podem não ser portáveis para trás, portanto podem exigir truques de compilação ou obter um compilador antigo e assim por diante, ou possivelmente em vez disso. compilando no sistema antigo. (Esse é um bom motivo para manter as máquinas virtuais antigas e antigas).
Arquitetura importa; O amd64 (ou IA-32) é muito diferente do ARM ou MIPS, portanto, não se espera que o binário de um deles seja executado em outro. No nível do assembly, a
main
seção do seu código no IA-32 compila viagcc -S code.c
paracom o qual um sistema amd64 pode lidar (em um sistema Linux - o OpenBSD, por outro lado, no amd64 não suporta binários de 32 bits; a compatibilidade retroativa com arcos antigos oferece aos atacantes espaço de manobra, por exemplo, CVE-2014-8866 e amigos). Enquanto isso, em um sistema MIPS big endian,
main
compila para:com o qual um processador Intel não tem idéia do que fazer e da mesma forma para o conjunto Intel no MIPS.
Você poderia usar o QEMU ou algum outro emulador para executar código estrangeiro (talvez muito, muito lentamente).
Contudo! Seu código é muito simples, portanto, haverá menos problemas de portabilidade do que qualquer outra coisa; programas normalmente fazem uso de bibliotecas que foram alteradas ao longo do tempo (glibc, openssl, ...); para aqueles que também precisam instalar versões mais antigas de várias bibliotecas (o RedHat, por exemplo, geralmente coloca "compat" em algum lugar do nome do pacote)
ou possivelmente se preocupe com as alterações ABI (Application Binary Interface) para coisas antigas que usam glibc ou alterações mais recentes devido ao C ++ 11 ou a outras versões do C ++. Também se pode compilar estático (aumentando muito o tamanho do binário no disco) para tentar evitar problemas de biblioteca, embora se algum binário antigo fizesse isso dependesse se a distribuição antiga do Linux estava compilando quase tudo dinâmico (RedHat: yes) ou não. Por outro lado, coisas como
patchelf
podem reativara.out
binários dinâmicos (ELF, mas provavelmente não formatados) para usar outras bibliotecas.Contudo! Ser capaz de executar um programa é uma coisa e, na verdade, fazer algo útil com outra. Os binários antigos da Intel de 32 bits podem ter problemas de segurança se dependerem de uma versão do OpenSSL que contenha algum problema de segurança horrível e não suportado, ou o programa talvez não consiga negociar com os servidores da Web modernos (como os modernos servidores rejeitam os antigos protocolos e cifras do programa antigo), ou o protocolo SSH versão 1 não é mais suportado ou ...
fonte
for GNU/Linux 2.6.32
(ou tal) na saída defile /usr/bin/ls
.Resumindo: se você estiver levando um binário compilado de um host para outro usando a mesma arquitetura (ou uma compatível) , pode ser perfeitamente bom levá-lo para outra distribuição . No entanto, à medida que a complexidade do código aumenta, a probabilidade de ser vinculado a uma biblioteca que não está instalada; instalado em outro local; ou instalado em uma versão diferente, aumenta. Tomando como exemplo o seu código, para o qual
ldd
relata as seguintes dependências quando compiladasgcc -o exit-test exit-test.c
em um host Ubuntu Linux (derivado do Debian):Obviamente, esse binário não funcionará se eu chutá-lo para, digamos, um Mac (
./exit-test: cannot execute binary file: Exec format error
). Vamos tentar movê-lo para uma caixa RHEL:Oh céus. Por que isso pode ser?
Mesmo para esse caso de uso, a empilhadeira falhou devido à falta de bibliotecas compartilhadas.
No entanto, se eu compilar
gcc -static exit-test-static exit-test.c
, transportá-lo para o sistema sem as bibliotecas funciona bem. À custa, é claro, de espaço em disco:Outra solução viável seria instalar as bibliotecas necessárias no novo host.
Tal como acontece com muitas coisas no universo U&L, este é um gato com muitas peles, duas das quais estão descritas acima.
fonte
amd64
binário e executá-lo em outraamd64
distribuição, ou construir umi386
binário e executá-lo em outrai386
distribuição.Além das excelentes respostas @thrig e @DopeGhoti: os sistemas operacionais Unix ou do tipo Unix, incluindo Linux, eram tradicionalmente sempre projetados e alinhados mais para a portabilidade do código-fonte do que os binários.
Se não houver nada específico de hardware ou uma fonte simples, como no exemplo, você pode movê-lo sem nenhum problema, entre praticamente qualquer versão do Linux ou arquitetura como código-fonte , desde que os servidores de destino tenham os pacotes de desenvolvimento C instalados , as bibliotecas necessárias e as bibliotecas de desenvolvimento correspondentes instaladas.
No que diz respeito à transferência de códigos mais avançados de versões antigas do Linux distantes no tempo ou de programas mais específicos, como módulos de kernel para diferentes versões de kernel, pode ser necessário adaptar e modificar o código-fonte para contabilizar as bibliotecas / APIs / ABIs obsoletas.
fonte
Por padrão , você quase certamente terá problemas com bibliotecas externas. Algumas das outras respostas entram em mais detalhes sobre esses problemas, então não vou duplicar o trabalho deles.
No entanto, você pode compilar muitos programas - mesmo os não triviais - para serem portáveis entre os sistemas Linux. A chave é o kit de ferramentas chamado Linux Standard Base . O LSB foi projetado para criar apenas esses tipos de aplicativos portáteis. Compile um aplicativo para LSB v5.0 e ele será executado em qualquer outro ambiente Linux (da mesma arquitetura) que implemente o LSB v5.0. Algumas distribuições Linux são compatíveis com LSB e outras incluem kits de ferramentas / bibliotecas LSB como um pacote instalável. Se você criar seu aplicativo usando as ferramentas LSB (como o
lsbcc
wrapper paragcc
) e vincular à versão LSB das bibliotecas, criará um aplicativo portátil.fonte
qemu
você mesmo pode executar programas compilados para archtecture diferente, (não alta performace, mas você pode executá-los)apt-get install
alguns pacotes.Talvez.
Coisas que tendem a quebrá-lo incluem.
Se você evitar o uso de bibliotecas que mudam rapidamente, evite alterações na arquitetura e, com base na distribuição mais antiga que você deseja atingir, terá uma boa chance de fazer um binário funcionar em muitas distribuições.
fonte
Além de algumas das coisas mencionadas anteriormente, houve algumas alterações no formato do arquivo executável. Na maioria das vezes, o linux usa ELF, mas versões mais antigas usavam a.out ou COFF.
O início de um wikihole:
https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats
Pode haver uma maneira de obter versões mais antigas para rodar formatos mais novos, mas eu pessoalmente nunca examinei isso.
fonte