Kurz gesagt:Wenn Sie eine kompilierte Binärdatei von einem Host auf einen anderen übertragen und dieselbe (oder eine kompatible) Architektur verwenden , können Sie es völlig in Ordnung zu einer anderen Distribution bringen . Mit zunehmender Komplexität des Codes steigt jedoch die Wahrscheinlichkeit, mit einer nicht installierten Bibliothek verknüpft zu werden; an einem anderen Ort installiert; oder auf einer anderen Version installiert, erhöht. Nehmen wir zum Beispiel Ihren Code, für den ldd
meldet die folgenden Abhängigkeiten, wenn es mit gcc -o exit-test exit-test.c
kompiliert wird auf einem (von Debian abgeleiteten) Ubuntu-Linux-Host:
$ 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)
Offensichtlich wird diese Binärdatei nicht ausgeführt, wenn ich sie beispielsweise auf einen Mac (./exit-test: cannot execute binary file: Exec format error
). Versuchen wir, es in eine RHEL-Box zu verschieben:
$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
Ach je. Warum könnte das so sein?
$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory
Selbst für diesen Anwendungsfall schlug das Forklifting aufgrund fehlender gemeinsam genutzter Bibliotheken fehl.
Wenn ich es jedoch mit gcc -static exit-test-static exit-test.c
kompiliere , das Portieren auf das System ohne die Bibliotheken funktioniert einwandfrei. Auf Kosten des Speicherplatzes natürlich:
$ 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
Eine andere praktikable Lösung wäre, die erforderlichen Bibliotheken auf dem neuen Host zu installieren.
Wie bei vielen Dingen im U&L-Universum ist dies eine Katze mit vielen Fellen, von denen zwei oben skizziert sind.
Es hängt davon ab, ob. Etwas, das für IA-32 (Intel 32-Bit) kompiliert wurde, kann auf AMD64 ausgeführt werden, da Linux auf Intel die Abwärtskompatibilität mit 32-Bit-Anwendungen behält (mit geeigneter installierter Software). Hier ist Ihr code
kompiliert auf einem RedHat 7.3 32-Bit-System (ca. 2002, gcc Version 2.96) und dann die Binärdatei auf ein Centos 7.4 64-Bit-System kopiert und darauf ausgeführt (ca. 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
Das alte RedHat 7.3 bis Centos 7.4 (im Wesentlichen RedHat Enterprise Linux 7.4) bleibt in der gleichen „Distributionsfamilie“, wird also wahrscheinlich eine bessere Portabilität aufweisen, als von einer zufälligen „Linux from scratch“-Installation aus dem Jahr 2002 zu einer anderen zufälligen Linux-Distribution im Jahr 2018 zu wechseln .
Etwas, das für AMD64 kompiliert wurde, würde nicht auf reinen 32-Bit-Versionen von Linux laufen (alte Hardware weiß nichts über neue Hardware). Dies gilt auch für neue Software, die auf modernen Systemen kompiliert wurde und dazu bestimmt ist, auf alten alten Geräten ausgeführt zu werden, da Bibliotheken und sogar Systemaufrufe möglicherweise nicht rückwärts portierbar sind und daher möglicherweise Kompilierungstricks erfordern oder einen alten Compiler usw. oder möglicherweise stattdessen benötigen Kompilieren auf dem alten System. (Dies ist ein guter Grund, virtuelle Maschinen von uralten alten Dingen zu behalten.)
Architektur spielt eine Rolle; AMD64 (oder IA-32) unterscheidet sich stark von ARM oder MIPS, sodass nicht erwartet wird, dass die Binärdatei von einem von ihnen auf einem anderen ausgeführt wird. Auf Assemblyebene der main
Abschnitt Ihres Codes auf IA-32 wird über gcc -S code.c
kompiliert zu
main:
pushl %ebp
movl %esp,%ebp
movl $99,%eax
popl %ebp
ret
mit denen ein amd64-System umgehen kann (auf einem Linux-System - OpenBSD dagegen auf amd64 nicht unterstützt 32-Bit-Binärdateien; Abwärtskompatibilität mit alten Archs gibt Angreifern Spielraum, z. CVE-2014-8866 und Freunde). Inzwischen auf einem Big-Endian-MIPS-System main
stattdessen kompiliert zu:
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
mit denen ein Intel-Prozessor nichts anzufangen weiß, und ebenso für die Intel-Baugruppe auf MIPS.
Sie könnten möglicherweise QEMU oder einen anderen Emulator verwenden, um fremden Code auszuführen (vielleicht sehr, sehr langsam).
Jedoch! Ihr Code ist sehr einfacher Code und wird daher weniger Portabilitätsprobleme haben als alles andere; Programme verwenden normalerweise Bibliotheken, die sich im Laufe der Zeit geändert haben (glibc, openssl, ...); für diese müssen möglicherweise auch ältere Versionen verschiedener Bibliotheken installiert werden (RedHat zum Beispiel fügt normalerweise "compat" irgendwo in den Paketnamen für solche ein)
compat-glibc.x86_64 1:2.12-4.el7.centos
oder machen Sie sich möglicherweise Gedanken über ABI-Änderungen (Application Binary Interface) für alte Dinge, die glibc verwenden, oder neuere Änderungen aufgrund von C++11 oder anderen C++-Versionen. Man könnte auch statisch kompilieren (die Binärgröße auf der Festplatte stark erhöhen), um zu versuchen, Bibliotheksprobleme zu vermeiden, aber ob eine alte Binärdatei dies getan hat, hängt davon ab, ob die alte Linux-Distribution fast alles dynamisch kompiliert hat (RedHat:ja) oder nicht. Andererseits Dinge wie patchelf
kann dynamisch rejiggern (ELF, aber wahrscheinlich nicht a.out
Format) Binärdateien, um andere Bibliotheken zu verwenden.
Jedoch! Ein Programm ausführen zu können, ist eine Sache, und tatsächlich etwas Nützliches damit zu tun, eine andere. Alte 32-Bit-Intel-Binärdateien können Sicherheitsprobleme haben, wenn sie von einer Version von OpenSSL abhängen, die ein schreckliches und nicht zurückportiertes Sicherheitsproblem enthält, oder das Programm kann überhaupt nicht mit modernen Webservern (wie die modernen Server lehnen die alten Protokolle und Chiffren des alten Programms ab), oder SSH-Protokoll Version 1 wird nicht mehr unterstützt, oder ...
Ergänzend zu den ausgezeichneten @thrig- und @DopeGhoti-Antworten:Unix oder Unix-ähnliche Betriebssysteme, einschließlich Linux, wurden traditionell immer mehr für die Portabilität von Quellcode als für Binärdateien entwickelt und ausgerichtet.
Wenn Sie nichts Hardwarespezifisches haben oder eine einfache Quelle wie in Ihrem Beispiel sind, können Sie sie problemlos zwischen so ziemlich beliebig verschieben Version von Linux oder Architektur als Quellcode solange auf den Zielservern die C-Entwicklungspakete installiert sind , die erforderlichen Bibliotheken und die entsprechenden Entwicklungsbibliotheken installiert.
Bei der Portierung von fortgeschrittenerem Code aus zeitlich entfernten älteren Linux-Versionen oder spezifischeren Programmen wie Kernel-Modulen für verschiedene Kernel-Versionen müssen Sie möglicherweise den Quellcode anpassen und modifizieren, um veraltete Bibliotheken/APIs/ABIs zu berücksichtigen.