Stručně řečeno:Pokud přenášíte zkompilovaný binární soubor z jednoho hostitele na druhého pomocí stejné (nebo kompatibilní) architektury , můžete být naprosto v pořádku, když si jej přenesete do jiné distribuce . Jak se však zvyšuje složitost kódu, pravděpodobnost propojení s knihovnou, která není nainstalována; instalován na jiném místě; nebo nainstalované v jiné verzi se zvyšuje. Vezměme si například váš kód, pro který je ldd
při kompilaci s gcc -o exit-test exit-test.c
hlásí následující závislosti na hostiteli Ubuntu Linux (odvozeném z Debianu):
$ ldd exit-test
linux-gate.so.1 => (0xb7748000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757b000)
/lib/ld-linux.so.2 (0x8005a000)
Tento binární soubor se samozřejmě nespustí, pokud jej překopnu, řekněme, na Mac (./exit-test: cannot execute binary file: Exec format error
). Zkusme to přesunout do boxu RHEL:
$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
Ach bože. Proč by to mohlo být?
$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory
I pro tento případ použití selhal vysokozdvižný vozík kvůli chybějícím sdíleným knihovnám.
Pokud to však zkompiluji s gcc -static exit-test-static exit-test.c
, jeho portování do systému bez knihoven funguje dobře. Samozřejmě na úkor místa na disku:
$ ls -l ./exit-test{,-static}
-rwxr-xr-x 1 username groupname 7312 Jan 29 14:18 ./exit-test
-rwxr-xr-x 1 username groupname 728228 Jan 29 14:27 ./exit-test-static
Dalším schůdným řešením by bylo nainstalovat potřebné knihovny na nového hostitele.
Stejně jako u mnoha věcí ve vesmíru U&L je to kočka s mnoha kůžemi, z nichž dvě jsou popsány výše.
Záleží. Něco kompilovaného pro IA-32 (Intel 32-bit) může běžet na amd64, protože Linux na Intelu si zachovává zpětnou kompatibilitu s 32bitovými aplikacemi (s nainstalovaným vhodným softwarem). Zde je váš code
zkompilován na 32bitovém systému RedHat 7.3 (cca 2002, gcc verze 2.96) a poté binární soubor zkopírován a spuštěn na 64bitovém systému Centos 7.4 (cca 2017):
-bash-4.2$ file code
code: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
-bash-4.2$ ./code
-bash: ./code: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
-bash-4.2$ sudo yum -y install glibc.i686
...
-bash-4.2$ ./code ; echo $?
99
Starověký RedHat 7.3 až Centos 7.4 (v podstatě RedHat Enterprise Linux 7.4) zůstává ve stejné „distribuční“ rodině, takže bude pravděpodobně mít lepší přenositelnost než přechod z nějaké náhodné instalace „Linux od nuly“ z roku 2002 do nějaké jiné náhodné distribuce Linuxu v roce 2018. .
Něco kompilovaného pro amd64 by nefungovalo na 32bitových verzích Linuxu (starý hardware neví o novém hardwaru). To platí také pro nový software kompilovaný na moderních systémech, které mají být provozovány na starých starých věcech, protože knihovny a dokonce i systémová volání nemusí být zpětně přenosná, takže mohou vyžadovat kompilační triky nebo získání starého kompilátoru a tak dále, nebo možná místo toho. kompilace na starém systému. (To je dobrý důvod, proč si ponechat virtuální stroje starých věcí.)
Na architektuře záleží; amd64 (nebo IA-32) se výrazně liší od ARM nebo MIPS, takže se neočekává, že by binární systém jednoho z nich běžel na jiném. Na úrovni sestavení main
část vašeho kódu na IA-32 se zkompiluje přes gcc -S code.c
do
main:
pushl %ebp
movl %esp,%ebp
movl $99,%eax
popl %ebp
ret
se kterými si systém amd64 poradí (na linuxovém systému -- OpenBSD na rozdíl od amd64 ne podpora 32bitových binárních souborů; zpětná kompatibilita se starými oblouky dává útočníkům prostor pro pohyb, např. CVE-2014-8866 a přátelé). Mezitím na big-endian MIPS systému main
místo toho se zkompiluje do:
main:
.frame $fp,8,$31
.mask 0x40000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
addiu $sp,$sp,-8
sw $fp,4($sp)
move $fp,$sp
li $2,99
move $sp,$fp
lw $fp,4($sp)
addiu $sp,$sp,8
j $31
nop
se kterým procesor Intel nebude mít ponětí, co má dělat, a stejně tak pro sestavu Intel na MIPS.
Ke spuštění cizího kódu byste mohli případně použít QEMU nebo nějaký jiný emulátor (možná velmi, velmi pomalu).
Nicméně! Váš kód je velmi jednoduchý kód, takže bude mít méně problémů s přenositelností než cokoli jiného; programy obvykle využívají knihovny, které se v průběhu času změnily (glibc, openssl, ...); pro ty může být také nutné nainstalovat starší verze různých knihoven (například RedHat pro takové typy obvykle uvádí "compat" někde v názvu balíčku)
compat-glibc.x86_64 1:2.12-4.el7.centos
nebo si možná dělat starosti se změnami ABI (Application Binary Interface) pro staré věci, které používají glibc, nebo novějšími změnami kvůli C++ 11 nebo jiným vydáním C++. Dalo by se také kompilovat statické (výrazně zvětšit binární velikost na disku), aby se zabránilo problémům s knihovnami, i když to, zda to dělala nějaká stará binární verze, závisí na tom, zda stará distribuce Linuxu kompilovala většinu všeho dynamického (RedHat:ano), nebo ne. Na druhou stranu věci jako patchelf
může znovu nastavit dynamické (ELF, ale pravděpodobně ne a.out
format) binární soubory k použití jiných knihoven.
Nicméně! Umět spustit program je jedna věc a druhá věc s ním skutečně dělat něco užitečného. Staré 32bitové binární soubory Intel mohou mít bezpečnostní problémy, pokud jsou závislé na verzi OpenSSL, která má v sobě nějaký hrozný a neportovaný bezpečnostní problém, nebo program nemusí být schopen vůbec vyjednávat s moderními webovými servery (jako moderní servery odmítají staré protokoly a šifry starého programu), nebo protokol SSH verze 1 již není podporován nebo ...
K vynikajícím odpovědím @thrig a @DopeGhoti dodáváme:Unixové nebo unixové operační systémy, včetně Linuxu, byly tradičně vždy navrženy a přizpůsobeny více pro přenositelnost zdrojového kódu než binární soubory.
Pokud nemáte nic specifického pro hardware nebo se jedná o jednoduchý zdroj jako ve vašem příkladu, můžete jej bez problémů přesunout z téměř jakéhokoli verze Linuxu nebo architektury jako zdrojového kódu pokud mají cílové servery nainstalované vývojové balíčky C , potřebné knihovny a nainstalované odpovídající vývojové knihovny.
Pokud jde o portování pokročilejšího kódu ze starších verzí Linuxu vzdálených v čase, nebo specifičtějších programů, jako jsou moduly jádra pro různé verze jádra, možná budete muset upravit a upravit zdrojový kód, aby zohlednil zastaralé knihovny/API/ABI.