Sind Binärdateien über verschiedene CPU-Architekturen portierbar?


16

Mein Ziel ist es, für Embedded Linux entwickeln zu können. Ich habe Erfahrung mit Bare-Metal-Embedded-Systemen mit ARM.

Ich habe einige allgemeine Fragen zur Entwicklung für verschiedene CPU-Ziele. Meine Fragen sind wie folgt:

  1. Wenn ich eine Anwendung kompiliert habe, die auf einem ' x86-Zielsystem, Linux-OS-Version xyz ' ausgeführt werden soll, kann ich dann dieselbe kompilierte Binärdatei auf einem anderen ' ARM-Zielsystem, Linux-OS-Version xyz ' ausführen ?

  2. Wenn dies nicht zutrifft, besteht die einzige Möglichkeit darin, den Quellcode der Anwendung mithilfe der entsprechenden Toolchain 'zum Beispiel arm-linux-gnueabi' neu zu erstellen / zu kompilieren.

  3. Ebenso kann ich, wenn ich ein ladbares Kernelmodul (Gerätetreiber) habe, das auf einem ' x86-Ziel, Linux-OS-Version xyz ' funktioniert, dasselbe kompilierte .ko auf einem anderen System ' ARM-Ziel, Linux-OS-Version xyz ' laden / verwenden. ?

  4. Wenn dies nicht zutrifft, besteht die einzige Möglichkeit darin, den Treiber-Quellcode mithilfe der entsprechenden Toolchain 'zum Beispiel arm-linux-gnueabi' neu zu erstellen / zu kompilieren.


27
nein ja nein ja
Hobbs

7
Es hilft zu erkennen, dass wir kein AMD-Ziel und kein Intel-Ziel haben, sondern nur ein einziges x86-Ziel für beide. Das liegt daran, dass Intel und AMD ausreichend kompatibel sind. Es wird dann offensichtlich, dass das ARM-Ziel aus einem bestimmten Grund existiert, nämlich weil ARM-CPUs nicht mit Intel / AMD / x86 kompatibel sind.
MSalters

1
Nein, es sei denn, es handelt sich um einen Bytecode, der für die Ausführung in einer tragbaren Laufzeitumgebung wie Java Runtime entwickelt wurde. Wenn Sie Code für die eingebettete Verwendung schreiben, basiert Ihr Code wahrscheinlich auf prozessorspezifischen Optimierungen oder Funktionen auf niedriger Ebene und ist nur schwer zu portieren. Dies erfordert mehr als nur die Kompilierung für die Zielplattform (z. B. Änderungen am Assemblycode, möglicherweise Neuschreiben) mehrere Module oder das gesamte Programm).
bwDraco

1
@MSalters: Tatsächlich haben wir ein AMD-Ziel: amd64, das häufig als x86-64 bezeichnet wird (während x86 normalerweise eine Umbenennung von i386 ist). Glücklicherweise hat Intel die AMD-Architektur kopiert (und später erweitert), sodass auf jedem 64-Bit-x86-System amd64-Binärdateien ausgeführt werden können.
Slebetman

Antworten:


42

Nein. Binärdateien müssen für die Zielarchitektur (neu) kompiliert werden, und Linux bietet nichts Besseres als sofort verfügbare Fat-Binärdateien . Der Grund dafür ist, dass der Code für eine bestimmte Architektur zu Maschinencode kompiliert wird und der Maschinencode zwischen den meisten Prozessorfamilien sehr unterschiedlich ist (z. B. ARM und x86 sind sehr unterschiedlich).

BEARBEITEN: Es ist erwähnenswert, dass einige Architekturen Abwärtskompatibilität bieten (und noch seltener Kompatibilität mit anderen Architekturen). Auf 64-Bit-CPUs ist die Abwärtskompatibilität mit 32-Bit-Editionen üblich (denken Sie jedoch daran, dass Ihre abhängigen Bibliotheken auch 32-Bit-Bibliotheken sein müssen, einschließlich Ihrer C-Standardbibliothek, sofern Sie keine statische Verknüpfung herstellen ). Erwähnenswert ist auch Itanium , wo x86-Code (nur 32-Bit) ausgeführt werden konnte, wenn auch sehr langsam. Die schlechte Ausführungsgeschwindigkeit von x86-Code war zumindest ein Grund dafür, dass er auf dem Markt nicht sehr erfolgreich war.

Beachten Sie, dass Sie Binärdateien, die mit neueren Anweisungen kompiliert wurden, auch in Kompatibilitätsmodi nicht für ältere CPUs verwenden können (z. B. können Sie AVX nicht in einer 32-Bit-Binärdatei auf Nehalem x86-Prozessoren verwenden ; die CPU unterstützt dies nur nicht.

Beachten Sie, dass Kernelmodule für die jeweilige Architektur kompiliert werden müssen. Außerdem funktionieren 32-Bit-Kernelmodule nicht auf 64-Bit-Kerneln oder umgekehrt.

Informationen zu kompilierungsübergreifenden Binärdateien (Sie müssen also keine Toolchain auf dem Ziel-ARM-Gerät haben) finden Sie in der umfassenden Antwort von grochmal weiter unten.


1
Es kann hilfreich sein, die Kompatibilität (oder das Fehlen) zwischen x86 und x64 zu klären, da einige x86-Binärdateien auf x64-Plattformen ausgeführt werden können. (Ich bin mir nicht sicher, ob dies unter Linux der Fall ist, aber zum Beispiel unter Windows.)
jpmc26

4
@ jpmc26 es ist unter Linux möglich; Möglicherweise müssen Sie zuerst Kompatibilitätsbibliotheken installieren. Die x86-Unterstützung ist ein nicht optionaler Bestandteil von Win64-Installationen. In Linux ist es optional; und weil die Linux-Welt bei der Bereitstellung von 64-Bit-Versionen von allem viel weiter fortgeschritten ist, haben manche Distributionen nicht standardmäßig (alle?) 32-Bit-Bibliotheken installiert. (Ich bin mir nicht sicher, wie häufig es ist; ich habe jedoch einige Fragen von Leuten gesehen, die vorher Mainstream-Distributionen betrieben haben.)
Dan Neely

@ jpmc26 Ich habe meine Antwort mit Ihren Notizen aktualisiert. Ich dachte darüber nach, das zu erwähnen, wollte aber die Antwort nicht komplizieren.
Elizafox

16

Elizabeth Myers ist richtig, jede Architektur erfordert eine kompilierte Binärdatei für die betreffende Architektur. Um Binärdateien für eine andere Architektur zu erstellen, als auf Ihrem System ausgeführt wird, benötigen Sie a cross-compiler.


In den meisten Fällen müssen Sie einen Cross-Compiler kompilieren. Ich habe nur Erfahrung mit gcc(aber ich glaube, dass llvmund andere Compiler ähnliche Parameter haben). Ein gccCross-Compiler wird erreicht, indem --targetder Konfiguration Folgendes hinzugefügt wird :

./configure --build=i686-arch-linux-gnu --target=arm-none-linux-gnueabi

Sie müssen kompilieren gcc, glibcund binutilsmit diesen Parametern (und die Kernel - Header des Kernels auf dem Zielcomputer zur Verfügung stellen).

In der Praxis ist dies erheblich komplizierter und auf verschiedenen Systemen treten unterschiedliche Erstellungsfehler auf.

Es gibt verschiedene Anleitungen zum Kompilieren der GNU-Toolchain, aber ich empfehle Linux From Scratch , das ständig gewartet wird und sehr gut erklärt, was die vorgestellten Befehle bewirken.

Eine weitere Option ist eine Bootstrap-Kompilierung eines Cross-Compilers. Dank des Kampfes um das Kompilieren von Cross-Compilern zu unterschiedlichen Architekturen wurden unterschiedliche Architekturen crosstool-nggeschaffen. Es gibt einen Bootstrap über die Toolchain, die zum Erstellen eines Cross-Compilers benötigt wird.

crosstool-ngUnterstützt mehrere Ziel-Triplets auf verschiedenen Architekturen. Im Grunde genommen handelt es sich um einen Bootstrap, bei dem die Benutzer ihre Zeit darauf verwenden, Probleme zu lösen, die beim Kompilieren einer Cross-Compiler-Toolchain auftreten.


Mehrere Distributionen stellen Cross-Compiler als Pakete zur Verfügung:

Mit anderen Worten, überprüfen Sie, was Ihre Distribution in Bezug auf Cross-Compiler zur Verfügung hat. Wenn Ihre Distribution keinen Cross-Compiler für Ihre Bedürfnisse hat, können Sie ihn jederzeit selbst kompilieren.

Verweise:


Kernelmodule beachten

Wenn Sie Ihren Cross-Compiler von Hand kompilieren, haben Sie alles, was Sie zum Kompilieren von Kernel-Modulen benötigen. Dies liegt daran, dass Sie die Kernel-Header zum Kompilieren benötigen glibc.

Wenn Sie jedoch einen von Ihrer Distribution bereitgestellten Cross-Compiler verwenden, benötigen Sie die Kernel-Header des Kernels, der auf dem Zielcomputer ausgeführt wird.


FWIW Fedora enthält auch Cross-Compiler.
Mattdm

@mattdm - danke, antworte gezwickt, ich glaube, ich habe den richtigen Teil des Fedora-Wikis verlinkt.
Grochmal

2
Eine einfachere Möglichkeit als Linux From Scratch, ein Linux und eine Toolchain für eine andere Architektur zu erhalten, ist crosstool-ng. Vielleicht möchten Sie das der Liste hinzufügen. Außerdem ist das manuelle Konfigurieren und Kompilieren einer GNU-übergreifenden Toolchain für eine bestimmte Architektur unglaublich aufwändig und weitaus mühsamer als nur das --targetErstellen von Flags. Ich vermute, das ist einer der Gründe, warum LLVM an Popularität gewinnt. Es ist so aufgebaut, dass Sie keine Neuerstellung benötigen, um auf eine andere Architektur abzuzielen. Stattdessen können Sie mehrere Backends mit derselben Frontend- und Optimierungsbibliothek abzielen.
Ich werde nicht existieren Idonotexist

@IwillnotexistIdonotexist - danke, ich habe die Antwort weiter optimiert. Ich habe noch nie von Crosstool-ng gehört, und es sieht sehr nützlich aus. Ihr Kommentar war für mich sehr hilfreich.
Grochmal

9

Beachten Sie, dass Sie als letzte Möglichkeit (dh wenn Sie nicht über den Quellcode verfügen) Binärdateien auf einer anderen Architektur mit Emulatoren wie qemu, dosboxoder ausführen können exagear. Einige Emulatoren sind so konzipiert, dass sie andere Systeme als Linux emulieren (z. B. dosboxMS-DOS-Programme ausführen, und es gibt zahlreiche Emulatoren für beliebte Spielekonsolen). Die Emulation hat einen erheblichen Performance-Overhead: Emulierte Programme laufen 2-10 mal langsamer als ihre nativen Gegenstücke.

Wenn Sie Kernelmodule auf einer nicht nativen CPU ausführen müssen, müssen Sie das gesamte Betriebssystem einschließlich des Kernels für dieselbe Architektur emulieren. AFAIK: Es ist unmöglich, fremden Code im Linux-Kernel auszuführen.


3
Die Geschwindigkeitsstrafe für die Emulation ist oftmals sogar 10x höher. Wenn Sie jedoch versuchen, Code auszuführen, der für einen 16-MHz-Computer auf einem 4-GHz-Computer geschrieben wurde (250: 1 Geschwindigkeitsunterschied), kann dies bei einem Emulator mit einer Geschwindigkeitsstrafe von 50: 1 der Fall sein Führen Sie Code viel schneller aus, als dies auf der ursprünglichen Plattform der Fall gewesen wäre.
Supercat

7

Binärdateien sind nicht nur nicht zwischen x86 und ARM portierbar, es gibt auch verschiedene ARM-Varianten .

In der Praxis werden Sie wahrscheinlich auf ARMv6 gegen ARMv7 stoßen. Raspberry Pi 1 ist ARMv6, spätere Versionen sind ARMv7. So ist es möglich, Code auf den späteren zu kompilieren, der auf dem Pi 1 nicht funktioniert.

Glücklicherweise besteht ein Vorteil von Open Source und Freier Software darin, dass Sie den Quellcode auf jeder Architektur neu erstellen können. Obwohl dies einige Arbeit erfordern kann.

(ARM-Versionierung ist verwirrend, aber wenn ein V vor der Nummer steht, handelt es sich um die Befehlssatzarchitektur (ISA). Wenn nicht, handelt es sich um eine Modellnummer wie "Cortex M0" oder "ARM926EJS". Modellnummern haben nichts zu tun tun mit ISA-Nummern.)


2
... und dann gibt es sogar verschiedene Unterarten für dieselbe ARM-Variante und sogar verschiedene ABIs für genau dieselbe Hardware (ich denke über die ganze ARM-Soft / Softfp / Hard-Fließkomma-Unordnung nach).
Matteo Italia

1
@ MatteoItalia Ugh. Die multiplen ABIs waren ein Snafu, eine Heilung für etwas, das schlimmer war als die Krankheit. Einige ARMs hatten überhaupt keine VFP- oder NEON-Register, einige hatten 16, einige 32. Auf Cortex-A8 und früheren Versionen lief die NEON-Engine ein Dutzend CCs hinter dem Rest des Kerns Menge. ARM hat es geschafft, das Richtige zu tun - eine große Anzahl gemeinsamer Funktionen zu fordern.
Ich werde nicht existieren Idonotexist

7

Sie müssen immer eine Plattform anvisieren . Im einfachsten Fall führt die Ziel-CPU den in der Binärdatei kompilierten Code direkt aus (dies entspricht in etwa den COM-Programmdateien von MS DOS). Betrachten wir zwei verschiedene Plattformen, die ich gerade erfunden habe - Waffenstillstand und Intellio. In beiden Fällen haben wir ein einfaches Hallo-Welt-Programm, das 42 auf dem Bildschirm ausgibt. Ich gehe auch davon aus, dass Sie plattformunabhängig eine Multi-Plattform-Sprache verwenden, sodass der Quellcode für beide gleich ist:

Print(42)

Bei Waffenstillstand gibt es einen einfachen Gerätetreiber, der sich um das Drucken von Zahlen kümmert. Sie müssen also nur auf einen Port ausgeben. In unserer portablen Assemblersprache würde dies etwa so aussehen:

out 1234h, 42

In einem Intellio-System gibt es jedoch keine solche Funktion, sodass es andere Ebenen durchlaufen muss:

mov a, 10h
mov c, 42
int 13h

Hoppla, wir haben bereits einen signifikanten Unterschied zwischen den beiden, bevor wir überhaupt zum Maschinencode kommen! Dies entspricht in etwa dem Unterschied zwischen Linux und MS DOS oder einem IBM PC und einer X-Box (auch wenn beide dieselbe CPU verwenden).

Aber dafür sind Betriebssysteme da. Nehmen wir an, wir haben eine HAL, die sicherstellt, dass alle unterschiedlichen Hardwarekonfigurationen auf der Anwendungsebene auf die gleiche Weise behandelt werden. Im Grunde genommen verwenden wir den Intellio-Ansatz auch im Waffenstillstand, und unser Code für "tragbare Baugruppen" ist derselbe. Dies wird sowohl von modernen Unix-ähnlichen Systemen als auch von Windows verwendet, häufig sogar in eingebetteten Szenarien. Gut - jetzt können wir auf Armistice und Intellio denselben wirklich portablen Assembler-Code haben. Aber was ist mit den Binärdateien?

Wie wir angenommen haben, muss die CPU die Binärdatei direkt ausführen. Schauen wir uns die erste Zeile unseres Codes mov a, 10hin Intellio an:

20 10

Oh. Es stellt sich heraus, dass mov a, constantes so beliebt ist, dass es eine eigene Anweisung mit einem eigenen Opcode hat. Wie geht der Waffenstillstand damit um?

36 01 00 10

Hmm. Da es den Opcode für gibt mov.reg.imm, benötigen wir ein anderes Argument, um das Register auszuwählen, dem wir zuweisen. Und die Konstante ist immer ein 2-Byte-Wort in Big-Endian-Notation - so wurde Waffenstillstand konstruiert. Tatsächlich sind alle Anweisungen in Waffenstillstand 4 Byte lang, keine Ausnahmen.

Stellen Sie sich nun vor, Sie führen die Binärdatei von Intellio im Waffenstillstand aus: Die CPU beginnt mit der Dekodierung des Befehls und findet den Opcode 20h. Im Waffenstillstand entspricht dies beispielsweise der and.imm.regAnweisung. Es wird versucht, die 2-Byte-Wortkonstante (die 10XXbereits ein Problem anzeigt) und dann die Registernummer (eine andere XX) zu lesen . Wir führen die falsche Anweisung mit den falschen Argumenten aus. Und was noch schlimmer ist, die nächste Anweisung wird völlig falsch sein, da wir tatsächlich eine andere Anweisung gegessen haben und dachten, es seien Daten.

Die Anwendung hat keine Chance zu funktionieren und wird höchstwahrscheinlich fast sofort abstürzen oder hängen bleiben.

Das bedeutet nicht, dass eine ausführbare Datei immer sagen muss, dass sie unter Intellio oder Armistice ausgeführt wird. Sie müssen lediglich eine Plattform definieren, die von der CPU unabhängig ist (wie bashunter Unix) oder sowohl von der CPU als auch vom Betriebssystem (wie Java oder .NET und heutzutage sogar von JavaScript). In diesem Fall kann die Anwendung eine ausführbare Datei für alle unterschiedlichen CPUs und Betriebssysteme verwenden, während sich auf dem Zielsystem eine Anwendung oder ein Dienst befindet (der direkt auf die richtige CPU und / oder das richtige Betriebssystem abzielt), der den plattformunabhängigen Code in etwas übersetzt CPU kann tatsächlich ausführen. Dies kann zu Leistungseinbußen, Kosteneinbußen oder Leistungseinbußen führen.

CPUs kommen normalerweise in Familien. Beispielsweise verfügen alle CPUs der x86-Familie über einen gemeinsamen Befehlssatz, der genau gleich codiert ist, sodass auf jeder x86-CPU jedes x86-Programm ausgeführt werden kann, sofern keine Erweiterungen verwendet werden (z. B. Gleitkomma- oder Vektoroperationen). Die gängigsten Beispiele für x86 sind heute natürlich Intel und AMD. Atmel ist ein bekanntes Unternehmen, das CPUs der ARM-Familie entwickelt und für Embedded-Geräte sehr beliebt ist. Apple hat beispielsweise auch eigene ARM-CPUs.

ARM ist jedoch absolut nicht mit x86 kompatibel - sie stellen sehr unterschiedliche Designanforderungen und haben nur sehr wenige Gemeinsamkeiten. Die Befehle haben völlig unterschiedliche Opcodes, sie werden auf unterschiedliche Weise dekodiert, die Speicheradressen werden unterschiedlich behandelt ... Es könnte möglich sein, eine Binärdatei zu erstellen, die sowohl auf einer x86-CPU als auch auf einer ARM-CPU ausgeführt wird, indem einige sichere Vorgänge verwendet werden zwischen den beiden unterscheiden und zu zwei völlig verschiedenen Anweisungssätzen springen, aber es bedeutet immer noch, dass Sie für beide Versionen separate Anweisungen haben, mit nur einem Bootstrapper, der zur Laufzeit den richtigen Satz auswählt.


3

Es ist möglich, diese Frage in eine vertraute Umgebung umzuwandeln. In Analogie:

"Ich habe ein Ruby-Programm, das ich ausführen möchte, aber meine Plattform verfügt nur über einen Python-Interpreter. Kann ich den Python-Interpreter verwenden, um mein Ruby-Programm auszuführen, oder muss ich mein Programm in Python neu schreiben?"

Eine Befehlssatzarchitektur ("Ziel") ist eine Sprache - eine "Maschinensprache" - und verschiedene CPUs implementieren verschiedene Sprachen. Das Auffordern einer ARM-CPU, eine Intel-Binärdatei auszuführen, ähnelt dem Versuch, ein Ruby-Programm mit einem Python-Interpreter auszuführen.


2

gcc verwendet die Begriffe "Architektur", um den "Befehlssatz" einer bestimmten CPU zu bezeichnen, und "Ziel" deckt die Kombination von CPU und Architektur zusammen mit anderen Variablen wie ABI, libc, endian-ness und mehr ab (möglicherweise einschließlich "Bare Metal"). Ein typischer Compiler verfügt über eine begrenzte Anzahl von Zielkombinationen (wahrscheinlich eine ABI, eine CPU-Familie, aber möglicherweise sowohl 32- als auch 64-Bit). Ein Cross-Compiler ist in der Regel entweder ein Compiler mit einem anderen Ziel als dem System, auf dem er ausgeführt wird, oder einer mit mehreren Zielen oder ABIs (siehe auch dies ).

Sind Binärdateien über verschiedene CPU-Architekturen portierbar?

Im Allgemeinen nicht. Eine Binärdatei ist im herkömmlichen Sinne der native Objektcode für eine bestimmte CPU oder CPU-Familie. Es gibt jedoch mehrere Fälle, in denen sie mäßig bis hochgradig portabel sind:

  • Eine Architektur ist eine Obermenge einer anderen (normalerweise sind x86-Binärdateien auf i386 oder i686 ausgerichtet und nicht auf die neueste und beste x86-Architektur, z. B. -march=core2)
  • Eine Architektur bietet native Emulation oder Übersetzung einer anderen (Sie haben vielleicht schon von Crusoe gehört ), oder sie bietet kompatible Co-Prozessoren (z. B. PS2 ).
  • Das Betriebssystem und die Laufzeit unterstützen Multiarch (z. B. die Möglichkeit, 32-Bit-x86-Binärdateien auf x86_64 auszuführen) oder das VM / JIT nahtlos zu machen (Android mit Dalvik oder ART ).
  • Es gibt Unterstützung für "fat" -Binaries, die im Wesentlichen doppelten Code für jede unterstützte Architektur enthalten

Wenn Sie es irgendwie schaffen, dieses Problem zu lösen, wird sich das andere tragbare Binärproblem von unzähligen Bibliotheksversionen (glibc ich sehe Sie an) zeigen. (Die meisten eingebetteten Systeme bewahren Sie zumindest vor diesem speziellen Problem.)

Wenn Sie es noch nicht getan haben, ist jetzt ein guter Zeitpunkt, um zu rennen gcc -dumpspecsund gcc --target-helpzu sehen, gegen was Sie antreten.

Fat Binaries haben verschiedene Nachteile , haben aber immer noch potenzielle Verwendungen ( EFI ).

Bei den anderen Antworten fehlen jedoch zwei weitere Überlegungen: ELF und der ELF-Interpreter sowie die Unterstützung des Linux-Kernels für beliebige Binärformate . Ich werde hier nicht näher auf Binärdateien oder Bytecode für nicht-reale Prozessoren eingehen, obwohl es möglich ist, diese als "native" zu behandeln und Java- oder kompilierte Python-Bytecode-Binärdateien auszuführen. Solche Binärdateien sind unabhängig von der Hardwarearchitektur (hängen jedoch stattdessen ab) auf der entsprechenden VM-Version, auf der letztendlich eine native Binärdatei ausgeführt wird).

Jedes moderne Linux-System verwendet ELF-Binärdateien (technische Details in diesem PDF ). Bei dynamischen ELF-Binärdateien ist der Kernel dafür verantwortlich, das Image in den Speicher zu laden, aber es ist die Aufgabe des in der ELF festgelegten Interpreters Header, um das schwere Heben zu tun. Normalerweise muss dafür gesorgt werden, dass alle abhängigen dynamischen Bibliotheken verfügbar sind (mithilfe des Abschnitts '' Dynamisch '', in dem die Bibliotheken und einige andere Strukturen mit den erforderlichen Symbolen aufgeführt sind) - dies ist jedoch fast eine allgemeine Indirektionsebene.

$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses \
shared libs), stripped
$ readelf -p .interp /bin/ls
    String dump of section '.interp':
      [     0]  /lib/ld-linux.so.2

( /lib/ld-linux.so.2Ist auch eine ELF-Binärdatei, hat keinen Interpreter und ist nativer Binärcode.)

Das Problem bei ELF ist, dass der Header in binary ( readelf -h /bin/ls) ihn für eine bestimmte Architektur, Klasse (32- oder 64-Bit), Endian-Ness und ABI kennzeichnet (Apples "universelle" Fat-Binaries verwenden ein alternatives Binärformat Mach-O) Stattdessen wurde dieses Problem durch NextSTEP gelöst. Dies bedeutet, dass eine ausführbare ELF-Datei mit dem System übereinstimmen muss, auf dem sie ausgeführt werden soll. Eine Escape-Luke ist der Interpreter. Dies kann eine beliebige ausführbare Datei sein (einschließlich einer, die architekturspezifische Unterabschnitte der ursprünglichen Binärdatei extrahiert oder abbildet und sie aufruft), Sie sind jedoch weiterhin durch die Art (en) der ELF eingeschränkt, die Ihr System ausführen darf . (FreeBSD hat eine interessante Art und Weise von Linux ELF - Dateien verarbeitet werden , der brandelfändert das ELF ABI Feld.)

Unter Linux wird Mach-O (mit binfmt_misc) unterstützt. Dort finden Sie ein Beispiel, das zeigt, wie Sie eine Fat-Binärdatei (32- und 64-Bit) erstellen und ausführen. Resource Forks / ADS , wie es ursprünglich auf dem Mac ausgeführt wurde, könnte eine Problemumgehung sein, aber kein natives Linux-Dateisystem unterstützt dies.

Mehr oder weniger dasselbe gilt für Kernelmodule, .koDateien sind ebenfalls ELF (obwohl sie keinen Interpreter-Satz haben). In diesem Fall gibt es eine zusätzliche Ebene, die die Kernel-Version ( uname -r) im Suchpfad verwendet. Dies könnte theoretisch stattdessen in ELF mit Versionierung erfolgen, aber mit einer gewissen Komplexität und wenig Gewinn, wie ich vermute.

Wie bereits an anderer Stelle erwähnt, unterstützt Linux Fat-Binaries nicht von Haus aus, es gibt jedoch ein aktives Fat-Binary-Projekt: FatELF . Es gibt es schon seit Jahren , es wurde nicht mehr in den Standard-Kernel integriert, was zum Teil auf (inzwischen abgelaufene) Patentprobleme zurückzuführen ist. Zu diesem Zeitpunkt sind sowohl Kernel- als auch Toolchain-Unterstützung erforderlich. Es wird nicht der binfmt_miscAnsatz verwendet, der die ELF-Header-Probleme umgeht und auch Fat-Kernel-Module zulässt.

  1. Wenn ich eine Anwendung kompiliert habe, um sie auf einem 'x86-Zielsystem, Linux-OS-Version xyz' auszuführen, kann ich dann dieselbe kompilierte Binärdatei auf einem anderen 'ARM-Zielsystem, Linux-OS-Version xyz' ausführen?

Nicht bei ELF, das lässt du nicht zu.

  1. Wenn dies nicht zutrifft, besteht die einzige Möglichkeit darin, den Quellcode der Anwendung mithilfe der entsprechenden Toolchain 'zum Beispiel arm-linux-gnueabi' neu zu erstellen / zu kompilieren.

Die einfache Antwort lautet ja. (Komplizierte Antworten umfassen Emulation, Zwischendarstellungen, Übersetzer und JIT. Abgesehen von der "Herabstufung" einer i686-Binärdatei zur Verwendung von i386-Opcodes sind sie hier wahrscheinlich nicht interessant, und die ABI-Korrekturen sind möglicherweise so schwierig wie die Übersetzung von nativem Code. )

  1. Ebenso kann ich, wenn ich ein ladbares Kernelmodul (Gerätetreiber) habe, das auf einem 'x86-Ziel, Linux-OS-Version xyz' funktioniert, dasselbe kompilierte .ko auf einem anderen System 'ARM-Ziel, Linux-OS-Version xyz' laden / verwenden. ?

Nein, ELF lässt dich das nicht tun.

  1. Wenn dies nicht zutrifft, besteht die einzige Möglichkeit darin, den Treiber-Quellcode mithilfe der entsprechenden Toolchain 'zum Beispiel arm-linux-gnueabi' neu zu erstellen / zu kompilieren.

Die einfache Antwort lautet ja. Ich glaube, mit FatELF können Sie eine .koMulti-Architektur erstellen , aber irgendwann muss eine Binärversion für jede unterstützte Architektur erstellt werden. Dinge, die Kernelmodule erfordern, kommen oft mit der Quelle und werden nach Bedarf erstellt, z. B. VirtualBox.

Dies ist bereits eine lange Antwort, es gibt nur noch einen Umweg. Im Kernel ist bereits eine virtuelle Maschine integriert, allerdings eine dedizierte: die BPF-VM , mit der Pakete abgeglichen werden. Der vom Menschen lesbare Filter "Host foo und nicht Port 22") wird zu einem Bytecode kompiliert und vom Kernel-Paketfilter ausgeführt . Das neue eBPF ist nicht nur für Pakete gedacht. Theoretisch ist VM-Code für alle gängigen Linux- Betriebssysteme portierbar und wird von llvm unterstützt. Aus Sicherheitsgründen ist es jedoch wahrscheinlich nicht für andere Zwecke als für Verwaltungsregeln geeignet.


Abhängig davon, wie großzügig Sie mit der Definition einer ausführbaren Binärdatei umgehen, können Sie (ab) verwenden binfmt_misc, um die Unterstützung für Fat Binary mit einem Shell-Skript und ZIP-Dateien als Container-Format zu implementieren:

#!/bin/bash

name=$1
prog=${1/*\//}      # basename
prog=${prog/.woz/}  # remove extension
root=/mnt/tmpfs
root=$(TMPDIR= mktemp -d -p ${root} woz.XXXXXX)
shift               # drop argv[0], keep other args

arch=$(uname -m)                  # i686
uname_s=$(uname -s)               # Linux
glibc=$(getconf GNU_LIBC_VERSION) # glibc 2.17
glibc=${glibc// /-}               # s/ /-/g

# test that "foo.woz" can unzip, and test "foo" is executable
unzip -tqq "$1" && {
  unzip -q -o -j -d ${root} "$1"  "${arch}/${uname_s}/${glibc}/*" 
  test -x ${root}/$prog && ( 
    export LD_LIBRARY_PATH="${root}:${LD_LIBRARY_PATH}"
    #readlink -f "${root}/${prog}"   # for the curious
    exec -a "${name}" "${root}/${prog}" "$@" 
  )
  rc=$?
  #rm -rf -- "${root}/${prog}"       # for the brave
  exit $rc
}

Nenne dies "wozbin" und richte es so ein:

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
printf ":%s:%s:%s:%s:%s:%s:%s" \
  "woz" "E" "" "woz" "" "/path/to/wozbin" ""  > /proc/sys/fs/binfmt_misc/register

Dadurch werden .wozDateien beim Kernel registriert. wozbinStattdessen wird das Skript mit dem ersten Argument aufgerufen , das auf den Pfad einer aufgerufenen .wozDatei festgelegt ist.

Um eine portable (fette) .woz Datei zu erhalten, erstellen Sie einfach eine test.wozZIP-Datei mit einer Verzeichnishierarchie.

i686/ 
    \- Linux/
            \- glibc-2.12/
armv6l/
    \- Linux/
            \- glibc-2.17/

Platzieren Sie in jedem arch / OS / libc-Verzeichnis (eine beliebige Auswahl) die architekturspezifische testBinärdatei und Komponenten wie z. B. .soDateien. Wenn Sie es aufrufen, wird das erforderliche Unterverzeichnis in ein speicherinternes tmpfs-Dateisystem ( /mnt/tmpfshier aktiviert) extrahiert und aufgerufen.


0

Berry Boot, lösen Sie einige Ihrer Probleme .. aber es ist kein Problem zu lösen, wie man auf Arm-hf, normaler / regulärer Linux-Distribution für x86-32 / 64bit läuft.

Ich denke, es sollte in Isolinux (Bootloader Linux auf USB) ein Live-Konverter eingebaut sein, der regullar Distribution erkennen und in Ride / Live in HF konvertieren könnte.

Warum? Denn wenn jedes Linux von berry boot auf arm-hf konvertiert werden kann, könnte es in der Lage sein, einen Bery-Boot-Mechanismus einzubauen, um das zu isolieren, was wir zum Beispiel für jeden booten, oder eine eingebaute Ubuntu Creat-Startdiskette.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.