Läuft eine auf einer Linux-Variante kompilierte ausführbare Linux-Datei auf einer anderen?

59

Läuft die ausführbare Datei eines kleinen, extrem einfachen Programms, wie das unten gezeigte, das auf einer Linux-Version kompiliert ist, auf einer anderen Version? Oder müsste es neu kompiliert werden?

Ist in einem solchen Fall die Maschinenarchitektur von Bedeutung?

int main()
{
  return (99);
}
JCDeen
quelle
2
Vielen Dank an alle für die hervorragenden Antworten! Ich habe viel mehr gelernt, als ich erwartet hatte. Ich habe den Code absichtlich künstlich einfach gemacht, damit er von möglichst wenigen Bibliotheken abhängt. aber das hätte ich eigentlich von vornherein sagen sollen. Die meisten meiner plattformübergreifenden C ++ - Codierungen wurden mit einem Microsoft-Tool wie Visual Studio entwickelt und anschließend auf ein * nix-System portiert und neu kompiliert.
JCDen
4
Die vielen hier zum Ausdruck gebrachten Facetten und Überlegungen haben mich erstaunt! Ich wünschte ehrlich, ich könnte mehrere als DIE Antwort wählen. Nochmals vielen Dank an alle! Mit freundlichen Grüßen.
JCDen
2
Android ist auch ein Linux-basiertes Betriebssystem. Viel Glück jedoch, wenn Sie Code ausführen, der dort kompiliert glibcwurde, oder umgekehrt. Zugegeben, das ist nicht ganz unmöglich .
undercat
2
Um die maximale Kompatibilität eines Befehlszeilentools zu gewährleisten, sollten Sie uClibc, musl oder dietlibc anstelle von glibc verwenden und Ihre 32-Bit-Programmdatei ( gcc -m32 -static) statisch verknüpfen . Auf diese Weise kann jedes i386- oder amd64-Linux die ausführbare Datei ausführen.
Pkt
10
Sie sollten 42 zurückkehren ! :)
Homunculus Reticulli

Antworten:

49

Es hängt davon ab, ob. Ein für IA-32 kompiliertes Produkt (Intel 32-Bit) kann unter amd64 ausgeführt werden, da Linux unter Intel die Abwärtskompatibilität mit 32-Bit-Anwendungen (mit geeigneter installierter Software) beibehält. Hier ist Ihr codeauf RedHat 7.3 32-Bit-System (ca. 2002, gcc-Version 2.96) kompiliertes und dann das Binärprogramm, das auf ein Centos 7.4 64-Bit-System (ca. 2017) kopiert und ausgeführt wird:

-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

Die alten Versionen von RedHat 7.3 bis Centos 7.4 (im Wesentlichen RedHat Enterprise Linux 7.4) gehören weiterhin zur selben "Distributions" -Familie, weshalb sie wahrscheinlich besser portiert werden können, als wenn sie ab 2002 von einer zufälligen "Linux from scratch" -Installation auf eine andere zufällige Linux-Distribution im Jahr 2018 umsteigen .

Etwas, das für amd64 kompiliert wurde, läuft nicht auf 32-Bit-Versionen von Linux (alte Hardware kennt keine neue Hardware). Dies gilt auch für neue Software, die auf modernen Systemen kompiliert wurde, die auf alten Dingen ausgeführt werden sollen, da Bibliotheken und sogar Systemaufrufe möglicherweise nicht rückwärts portierbar sind und daher Kompilierungstricks oder den Erwerb eines alten Compilers usw. erfordern Kompilieren auf dem alten System. (Dies ist ein guter Grund, virtuelle Maschinen mit alten Dingen in der Nähe zu halten.)

Architektur ist wichtig; amd64 (oder IA-32) unterscheidet sich stark von ARM oder MIPS, so dass nicht erwartet wird, dass die Binärdatei auf einer anderen ausgeführt wird. Auf der Assembly-Ebene wird der mainAbschnitt Ihres Codes auf IA-32 über gcc -S code.cto kompiliert

main:
    pushl %ebp
    movl %esp,%ebp
    movl $99,%eax
    popl %ebp
    ret

mit denen ein amd64-System umgehen kann (auf einem Linux-System - OpenBSD unterstützt im Gegensatz zu amd64 keine 32-Bit-Binärdateien; Abwärtskompatibilität mit alten Archs lässt Angreifern Spielraum, z. B. CVE-2014-8866 und Freunden). In der Zwischenzeit wird auf einem Big-Endian-MIPS-System main Folgendes kompiliert:

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

Womit ein Intel-Prozessor keine Ahnung haben wird, was zu tun ist, und ebenfalls für die Intel-Baugruppe auf MIPS.

Sie könnten möglicherweise QEMU oder einen anderen Emulator verwenden, um Fremdcode auszuführen (möglicherweise sehr, sehr langsam).

Jedoch! Ihr Code ist sehr einfach und hat daher weniger Portabilitätsprobleme als alles andere. Programme verwenden normalerweise Bibliotheken, die sich im Laufe der Zeit geändert haben (glibc, openssl, ...). Für diese muss möglicherweise auch eine ältere Version verschiedener Bibliotheken installiert werden (RedHat setzt zum Beispiel typischerweise "compat" irgendwo in den Paketnamen für solche).

compat-glibc.x86_64                     1:2.12-4.el7.centos

oder möglicherweise über ABI-Änderungen (Application Binary Interface) besorgt sein, die sich auf ältere Dinge beziehen, die glibc verwenden, oder auf Änderungen, die in jüngster Zeit aufgrund von C ++ 11 oder anderen C ++ - Versionen vorgenommen wurden. Man könnte auch statisch kompilieren (was die Binärgröße auf der Festplatte stark erhöht), um Bibliotheksprobleme zu vermeiden. Ob dies jedoch durch eine alte Binärdatei geschehen ist, hängt davon ab, ob die alte Linux-Distribution fast alles Dynamische kompiliert hat (RedHat: yes) oder nicht. Auf der anderen Seite können Dinge wie patchelfdynamische (ELF, aber wahrscheinlich nicht a.outformatierte) Binärdateien rejiggern , um andere Bibliotheken zu verwenden.

Jedoch! In der Lage zu sein, ein Programm auszuführen, ist eine Sache und damit etwas Nützliches zu tun eine andere. Alte 32-Bit-Binärdateien von Intel können Sicherheitsprobleme aufweisen, wenn sie von einer OpenSSL-Version abhängen, die ein schreckliches und nicht rückportiertes Sicherheitsproblem aufweist, oder wenn das Programm überhaupt nicht mit modernen Webservern (wie den modernen) verhandeln kann Server lehnen die alten Protokolle und Chiffren des alten Programms ab, oder SSH-Protokoll Version 1 wird nicht mehr unterstützt, oder ...

Thrig
quelle
14
Zu Absatz 1: Nein, Intel nennt es "Intel 64" (in diesen Tagen, nachdem wir einige andere Namen zuvor durchgesehen haben). IA-64 bezieht sich auf Itanium, nicht auf x86-kompatible Geräte.
Hobbs
1
@hobbs danke, ich habe diese Verweise durch amd64 ersetzt; Ich überlasse die Benennung der Dinge der Intel-Marketingabteilung.
Am
3
Warum nicht die statische Verknüpfung erwähnen?
dcorking
2
Nicht nur Bibliotheks-ABIs ändern sich, auch die Syscall-Schnittstelle des Kernels wird im Laufe der Zeit erweitert. Beachten Sie die for GNU/Linux 2.6.32(oder solche) in der Ausgabe von file /usr/bin/ls.
Charles Duffy
1
@Wilbert Vermutlich fehlt Ihnen, dass Thrig sich auf Red Hat Linux bezog, das sich von Red Hat Enterprise Linux unterscheidet.
Bob
68

Kurz gesagt: Wenn Sie eine kompilierte Binärdatei mit derselben (oder einer kompatiblen) Architektur von einem Host auf einen anderen übertragen , ist es möglicherweise in Ordnung, sie auf eine andere Distribution zu übertragen . 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 in einer anderen Version installiert, erhöht. Nehmen wir zum Beispiel Ihren Code, für lddden beim Kompilieren gcc -o exit-test exit-test.cauf einem (von Debian abgeleiteten) Ubuntu-Linux-Host die folgenden Abhängigkeiten gemeldet werden :

$ 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 einem Mac ( ./exit-test: cannot execute binary file: Exec format error) übergebe. Lassen Sie uns versuchen, 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 Gabelstaplern aufgrund fehlender gemeinsamer Bibliotheken fehl.

Wenn ich es jedoch mit kompiliere gcc -static exit-test-static exit-test.c, funktioniert das Portieren auf das System ohne die Bibliotheken einwandfrei. Natürlich auf Kosten des Speicherplatzes:

$ 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 Installation der erforderlichen Bibliotheken auf dem neuen Host.

Wie bei vielen Dingen im U & L-Universum ist dies eine Katze mit vielen Häuten, von denen zwei oben aufgeführt sind.

DopeGhoti
quelle
4
In der Tat habe ich statische Binärdateien vergessen. Einige Anbieter verwenden statische Binärdateien und einige Malware-Autoren auch, um die Binärkompatibilität zwischen Linux-Versionen derselben Architektur
Rui F Ribeiro
8
Gabelstapler fahren ...?
user253751
2
@immibis Ich denke, es bedeutet das Kopieren von Daten (der ausführbaren Datei) von einer Umgebung (Distribution) in eine andere, wo die Daten nicht für die Zielumgebung ausgelegt sind.
wjandrea
13
Ihr Linux-Beispiel ist leider ziemlich künstlich und zeigt, dass Sie sich eher mit Architekturen als mit Distributionen befassen: Sie haben eine 32-Bit-Binärdatei unter Debian erstellt und versucht, sie unter 64-Bit-RHEL auszuführen; Das sind verschiedene Architekturen ... Binärdateien mit derselben Architektur und so wenigen Bibliotheksabhängigkeiten können problemlos kopiert werden.
Stephen Kitt
7
@MSalters Ich sage nicht, dass es unvernünftig ist, ich sage, dass es ein schlechtes Beispiel ist, wenn man bedenkt, dass DopeGhoti versucht, dies zu tun (Sie können keine Binärdateien von einer Distribution in eine andere kopieren - was falsch ist). Natürlich unterstützt 64-Bit-Linux auf Intel auch die Ausführung von 32-Bit-ausführbaren Dateien mit der entsprechenden Infrastruktur. Ein gültiges Beispiel in diesem Fall wäre IMO, eine amd64Binärdatei zu erstellen und auf einer anderen amd64Distribution auszuführen, oder eine i386Binärdatei zu erstellen und auf einer anderen Distribution i386auszuführen.
Stephen Kitt
25

Ergänzend zu den hervorragenden Antworten von @thrig und @DopeGhoti: Unix oder Unix-ähnliche Betriebssysteme, einschließlich Linux, wurden traditionell eher für die Portierbarkeit von Quellcode als für Binärdateien entwickelt und ausgerichtet.

Wenn Sie keine bestimmte Hardware haben oder eine einfache Quelle wie in Ihrem Beispiel sind, können Sie diese problemlos zwischen nahezu jeder Linux- oder Architekturversion als Quellcode verschieben, sofern auf den Zielservern die C-Entwicklungspakete installiert sind. die erforderlichen Bibliotheken und die entsprechenden installierten Entwicklungsbibliotheken.

Wenn Sie fortgeschritteneren Code aus älteren Linux-Versionen oder spezifischere Programme wie Kernelmodule für verschiedene Kernelversionen portieren möchten, müssen Sie möglicherweise den Quellcode anpassen und ändern, um veraltete Bibliotheken / APIs / ABIs zu berücksichtigen.

Rui F Ribeiro
quelle
19

Mit dem Standard werden Sie mit ziemlicher Sicherheit Probleme mit externen Bibliotheken laufen. Einige der anderen Antworten gehen näher auf diese Probleme ein, sodass ich ihre Arbeit nicht duplizieren werde.

Sie können jedoch viele - auch nicht triviale - Programme kompilieren, um sie zwischen Linux-Systemen zu portieren. Der Schlüssel ist das als Linux Standard Base bezeichnete Toolkit . Das LSB ist für die Erstellung genau dieser Arten von tragbaren Anwendungen ausgelegt. Kompilieren Sie eine Anwendung für LSB v5.0, und sie kann in jeder anderen Linux-Umgebung (mit derselben Architektur) ausgeführt werden, in der LSB v5.0 implementiert ist. Einige Linux-Distributionen sind LSB-kompatibel, andere enthalten LSB-Toolkits / -Bibliotheken als installierbares Paket. Wenn Sie Ihre Anwendung mit den LSB-Tools (wie dem lsbccWrapper für gcc) erstellen und eine Verknüpfung zur LSB-Version der Bibliotheken herstellen, erstellen Sie eine portable Anwendung.

bta
quelle
und mit können qemuSie sogar Programme ausführen, die für verschiedene Architekturen kompiliert wurden (keine hohe Leistung, aber Sie können sie ausführen)
Jasen
1
Das Linux Standard Base-Toolkit war mir nicht einmal bekannt. Vielen Dank! Ich habe vor langer Zeit angefangen, mit C / C ++ zu arbeiten. Viele der Informationen in diesen Antworten sind für mich neu. Und sehr hilfreich.
JCDen
1
Der Wikipedia-Artikel besagt, dass Debian und Ubuntu LSB nicht implementieren (und dies auch nicht beabsichtigen).
BlackJack
2
@ BlackJack- Die Distribution selbst implementiert nicht 100% davon als Teil des Kernbetriebssystems, aber Sie können LSB-Kompatibilitätsbibliotheken und Toolkits als optionale Pakete installieren. Ich habe Ubuntu (zum Beispiel) verwendet, um LSB-kompatible Programme zu erstellen, die dann unter Suse und Centos ausgeführt wurden. Sie benötigen nur apt-get installein paar Pakete.
bta
10

Vielleicht.

Dinge, die dazu neigen, es zu brechen, gehören.

  1. Unterschiedliche Architekturen. Ganz andere Architekturen funktionieren natürlich nicht (es sei denn, Sie haben so etwas wie den Benutzermodus qemu mit binfmt_misc, aber das ist kaum eine normale Konfiguration). x86-Binärdateien funktionieren möglicherweise unter amd64, jedoch nur, wenn die erforderlichen 32-Bit-Bibliotheken verfügbar sind.
  2. Bibliotheksversionen. Wenn die Soversion falsch ist, wird die Bibliothek überhaupt nicht gefunden. Wenn die Version identisch ist, die Binärdatei jedoch für eine neuere Version der Bibliothek erstellt wurde, als für die sie ausgeführt wird, kann sie möglicherweise nicht geladen werden, da neue Symbole oder neue Versionen von Symbolen vorhanden sind. Insbesondere glibc ist ein starker Benutzer von Symbolversionen. Daher ist es sehr wahrscheinlich, dass Binärdateien, die gegen eine neuere glibc erstellt wurden, mit einer älteren glibc fehlschlagen.

Wenn Sie es vermeiden, sich schnell ändernde Bibliotheken zu verwenden, vermeiden Sie Änderungen der Architektur und bauen Sie auf der ältesten Distribution auf, auf die Sie abzielen möchten. Sie haben gute Chancen, dass eine Binärdatei auf vielen Distributionen funktioniert.

Plugwash
quelle
4

Zusätzlich zu einigen der zuvor erwähnten Dinge gab es einige Änderungen im ausführbaren Dateiformat. In den meisten Fällen verwendet Linux ELF, in älteren Versionen jedoch a.out oder COFF.

Der Beginn eines Wikilochs:

https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats

Es könnte eine Möglichkeit geben, ältere Versionen dazu zu bringen, neuere Formate auszuführen, aber ich persönlich habe mich noch nie damit befasst.

Ben
quelle
"älter" ist zu diesem Zeitpunkt allerdings schon sehr alt.
Plugwash