Wie ist Mono magisch?

149

Ich lerne C #, deshalb habe ich ein kleines C # -Programm erstellt, in dem steht, dass ich es Hello, World!kompiliert mono-cscund ausgeführt habe mit mono:

$ mono-csc Hello.cs
$ mono Hello.exe
Hello, World!

Ich bemerkte , dass , wenn ich traf TABin bash, Hello.exewurde ausführbar markiert. Tatsächlich läuft es nur mit einer Shell, die den Dateinamen lädt!

Hello.exeist keine ELF-Datei mit einer lustigen Dateierweiterung:

$ readelf -a Hello.exe
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
$ xxd Hello.exe | head -n1
00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000  MZ..............

MZbedeutet, dass es sich um eine statisch verknüpfte ausführbare Datei von Microsoft Windows handelt. Legen Sie es auf einer Windows-Box ab, und es wird (sollte) ausgeführt.

Ich habe wineinstalliert, aber wineeine Kompatibilitätsschicht für Windows - Anwendungen ist, dauert etwa 5 - fach so lange laufen , Hello.exewie monound Ausführung direkt zu tun, so ist es nicht , winedass es läuft.

Ich gehe davon aus, dass ein monoKernelmodul installiert ist mono, das den exec/ die Syscall / s abfängt oder Binärdateien abfängt , die mit beginnen 4D 5A, aber lsmod | grep monoFreunde geben einen Fehler zurück.

Was ist hier los und woher weiß der Kernel, dass diese ausführbare Datei etwas Besonderes ist?


Nur zum Beweis, dass es nicht meine Shell-Arbeitsmagie ist, habe ich die Crap Shell (aka sh) verwendet, um sie auszuführen, und sie läuft immer noch nativ.


Hier ist das Programm vollständig, da ein Kommentator neugierig war:

using System;

class Hello {
  /// <summary>
  ///   The main entry point for the application
  /// </summary>
  [STAThread]
  public static void Main(string[] args) {
    System.Console.Write("Hello, World!\n");
  }
}
Katze
quelle
4
Sie haben zwar eine Antwort bekommen, aber ich bin ein bisschen verwirrt. Wenn Sie die Befehle wie php hello.phpoder python hello.pyoder perl hello.ploder im Falle einer kompilierten Sprache wie Java java helloausführen, werden sie auch ausgeführt, da sie dort keine ausführbare Datei sind, sondern ein Programm zum Lesen und Ausführen einer Datei. Wenn Sie jedoch ./hello.exeanstelle von ausführen, mono hello.exefand ich Ihre Frage und akzeptierte Antwort vernünftiger (die auf jeden Fall binfmt-Unterstützung verwenden.
kuldeep.kamboj
@ kuldeep.kamboj Ich bin nicht sicher, ob ich verstehe, was Sie sagen, aber ich war nur überrascht, dass eine ausführbare Windows-Datei "nativ" auf einer Linux-Box ausgeführt wird.
Katze
1
Eigentlich habe ich gesagt, dass jede Codedatei (oder kompilierte Datei) über ihr Programm im Format ausgeführt werden kann program codefile, in Ihrem Fall ist das Programm mono, während meine Beispiele PHP, Python, Perl und Java enthalten. Ich vermute, wenn Mono die Erweiterung auf eine andere als die EXE-Datei zulässt, die immer noch über Code ausgeführt wird. Es sollte überhaupt nicht von Windows abhängen, da letztendlich ein kompilierter Code ausgeführt wird. Wenn Ihre Quelldatei jedoch einen abhängigen Code hat, wie z. B. nur Windows-APIs, müssen Sie Wein zum Ausführen dieser Exe-Datei benötigen.
kuldeep.kamboj
4
Ein Teil der wunderbaren Ironie dabei ist, dass /etc/magicoder /usr/share/file/magic(oder ein ähnlicher magischer Ort) die Datei enthält, die die Informationen enthält, die erforderlich sind, um dies zu tun.
1
@cat ist eine sehr interessante Datei (wenn ich eine Lieblingsdatei hätte, wäre sie wahrscheinlich meine erste Wahl). Es enthält die Informationen zum Identifizieren aller Arten von Dateien. Sie müssen jedoch zuerst ermitteln, was die Datei ist, bevor Sie herausfinden können, wie sie ausgeführt wird. Das ist es, was Datei und ihre Magie bewirken. Eine ähnliche Sache - Java Binary Kernel Support für Linux von einer Weile her, so dass Sie dies $ foo.jareher tun könnten als $ java -jar foo.jar- ähnlich wie bei Mono.

Antworten:

183

Dies ist binfmt_misc in Aktion: Hiermit kann der Kernel erfahren, wie er unbekannte Binärdateien ausführt. Schauen Sie sich den Inhalt von an /proc/sys/fs/binfmt_misc. Unter den dort angezeigten Dateien sollte erklärt werden, wie Mono-Binärdateien ausgeführt werden:

enabled
interpreter /usr/lib/binfmt-support/run-detectors
flags:
offset 0
magic 4d5a

(auf einem Debian-System). Dies teilt dem Kernel mit, dass Binärdateien, die mit MZ( 4d5a) beginnen, übergeben werden sollen run-detectors. Letzteres ermittelt, ob Mono oder Wine zum Ausführen der Binärdatei verwendet werden soll.

Binärtypen können jederzeit hinzugefügt, entfernt, aktiviert und deaktiviert werden. Einzelheiten finden Sie in der Dokumentation oben (die Semantik ist überraschend, das hier verwendete virtuelle Dateisystem verhält sich nicht ganz wie ein Standard-Dateisystem). /proc/sys/fs/binfmt_misc/statusgibt den globalen Status an und jeder binäre "Deskriptor" zeigt seinen individuellen Status an. Eine andere Möglichkeit zum Deaktivieren binfmt_miscbesteht darin, das Kernelmodul zu entladen, wenn es als Modul erstellt wurde. Dies bedeutet auch, dass es möglich ist, eine schwarze Liste zu erstellen, um dies vollständig zu vermeiden.

Mit dieser Funktion können neue Binärtypen unterstützt werden, z. B. ausführbare MZ-Dateien (einschließlich Windows PE- und PE + -Binärdateien, aber auch DOS- und OS / 2-Binärdateien!), Java-JAR-Dateien. Außerdem können bekannte Binärtypen unterstützt werden neue Architekturen, typischerweise mit Qemu; Auf diese Weise können Sie mit den entsprechenden Bibliotheken ARM Linux-Binärdateien auf einem Intel-Prozessor transparent ausführen!

Ihre Frage ergab sich aus der Cross-Kompilierung, wenn auch im .NET-Sinne, und führt zu einer Einschränkung binfmt_misc: Einige Konfigurationsskripte verhalten sich falsch, wenn Sie versuchen, eine Cross-Kompilierung auf einem System durchzuführen, auf dem die cross-kompilierten Binärdateien ausgeführt werden können. In der Regel müssen Sie zum Erkennen einer Kreuzkompilierung eine Binärdatei erstellen und versuchen, diese auszuführen. Wenn es läuft, werden Sie nicht überkompiliert. Wenn es nicht läuft, sind Sie (oder Ihr Compiler ist kaputt). autoconfSkripte können in diesem Fall normalerweise durch explizite Angabe der Build- und Host-Architektur behoben werden. Manchmal müssen Sie sie jedoch binfmt_miscvorübergehend deaktivieren .

Stephen Kitt
quelle
2
Für diejenigen, die neugierig auf / proc sind, könnte es von Interesse sein, wie / proc / * funktioniert. auf Super User .
ein Lebenslauf