GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Läuft eine ausführbare Linux-Datei, die auf einer Linux-Variante kompiliert wurde, auf einer anderen?

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.


Linux
  1. Einfacher Linux-Befehl, der mir sagt, was der Display Manager ist?

  2. Linux – Mac OS X-Anwendungen unter Linux ausführen?

  3. Linux – Wie testet man, ob eine Linux-Binärdatei als positionsunabhängiger Code kompiliert wurde?

  4. Linux – Wird eine ausführbare Linux-Datei, die auf einer „Variante“ von Linux kompiliert wurde, auf einer anderen laufen?

  5. Wie führe ich ein Programm mit einem anderen Arbeitsverzeichnis als dem aktuellen aus, von der Linux-Shell?

So führen Sie Windows 95 unter Linux aus

So führen Sie mehrere Linux-Befehle in einem einzigen Befehl aus

Befehl, der Linux dazu zwingt, den Cache einer Datei auf einer NFS-Freigabe zu leeren?

Linux – Sind verschiedene Linux/Unix-Kernel austauschbar?

Best Practice zum Ausführen des Linux-Dienstes als ein anderer Benutzer

Kann einer der Windows-Failoverclusterknoten unter Linux ausgeführt werden?