Sto imparando C#, quindi ho creato un programmino C# che dice Hello, World!
, quindi compilato con mono-csc
ed eseguilo con mono
:
$ mono-csc Hello.cs
$ mono Hello.exe
Hello, World!
L'ho notato quando ho premuto TAB
in bash
, Hello.exe
è stato contrassegnato come eseguibile. In effetti, funziona solo con una shell che carica il nome del file!
Hello.exe
è non un file ELF con un'estensione di file divertente:
$ 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..............
MZ
significa che è un eseguibile collegato staticamente di Microsoft Windows. Rilascialo su una finestra di Windows e (dovrebbe) funzionare.
Ho wine
installato, ma wine
, essendo un livello di compatibilità per le app di Windows, impiega circa 5 volte il tempo per eseguire Hello.exe
come mono
ed eseguirlo direttamente lo fa, quindi non è wine
che lo esegue.
Presumo che ci sia del mono
modulo del kernel installato con mono
che intercetta il exec
syscall/s, o cattura i binari che iniziano con 4D 5A
, ma lsmod | grep mono
e gli amici restituiscono un errore.
Cosa sta succedendo qui e come fa il kernel a sapere che questo eseguibile è speciale?
Solo per prova che non è mio shell che funziona con la magia, ho usato la Crap Shell (aka sh
) per eseguirlo e funziona ancora in modo nativo.
Ecco il programma per intero, visto che un commentatore era curioso:
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");
}
}
Risposta accettata:
Questo è binfmt_misc in azione:permette di dire al kernel come eseguire binari di cui non è a conoscenza. Guarda il contenuto di /proc/sys/fs/binfmt_misc
; tra i file che vedi lì, uno dovrebbe spiegare come eseguire i binari Mono:
enabled
interpreter /usr/lib/binfmt-support/run-detectors
flags:
offset 0
magic 4d5a
(su un sistema Debian). Questo dice al kernel che i binari iniziano con MZ
(4d5a
) deve essere assegnato a run-detectors
. Quest'ultimo decide se utilizzare Mono o Wine per eseguire il binario.
I tipi binari possono essere aggiunti, rimossi, abilitati e disabilitati in qualsiasi momento; vedere la documentazione sopra per i dettagli (la semantica è sorprendente, il filesystem virtuale utilizzato qui non si comporta del tutto come un filesystem standard). /proc/sys/fs/binfmt_misc/status
fornisce lo stato globale e ogni "descrittore" binario mostra il suo stato individuale. Un altro modo per disabilitare binfmt_misc
è scaricare il suo modulo del kernel, se è compilato come modulo; questo significa anche che è possibile inserirlo nella blacklist per evitarlo del tutto.
Questa funzione consente di supportare nuovi tipi binari, come eseguibili MZ (che includono binari Windows PE e PE+, ma anche binari DOS e OS/2!), file Java JAR... Consente inoltre di supportare tipi binari noti su nuove architetture , tipicamente usando Qemu; quindi, con le librerie appropriate, puoi eseguire in modo trasparente i binari di ARM Linux su un processore Intel!
Relazionato:Cheat Sheet di Linux Things I Forget
La tua domanda derivava da una compilazione incrociata, anche se in senso .NET, e questo fa apparire un avvertimento con binfmt_misc
:alcuni script di configurazione si comportano in modo anomalo quando si tenta di eseguire la compilazione incrociata su un sistema che può eseguire i binari della compilazione incrociata. In genere, il rilevamento della compilazione incrociata implica la creazione di un file binario e il tentativo di eseguirlo; se funziona, non stai compilando in modo incrociato, in caso contrario, lo sei (o il tuo compilatore è rotto). autoconf
gli script di solito possono essere corretti in questo caso specificando esplicitamente la build e le architetture host, ma a volte dovrai disabilitare binfmt_misc
temporaneamente...