J'apprends le C #, j'ai donc créé un petit programme C # qui dit Hello, World!
, puis compilé avec mono-csc
et l'a exécuté avec mono
:
$ mono-csc Hello.cs
$ mono Hello.exe
Hello, World!
J'ai remarqué que lorsque j'ai touché TAB
dans bash
, Hello.exe
était marqué comme exécutable. En effet, il s'exécute par un simple shell chargeant le nom de fichier!
Hello.exe
n'est pas un fichier ELF avec une extension de fichier amusante:
$ 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
signifie qu'il s'agit d'un exécutable Microsoft Windows lié statiquement. Déposez-le sur une boîte Windows et il fonctionnera (devrait).
J'ai wine
installé, mais wine
, étant une couche de compatibilité pour les applications Windows, prend environ 5 fois plus de temps pour s'exécuter Hello.exe
comme mono
et en l'exécutant directement, donc ce n'est pas wine
qui l'exécute.
Je suppose qu'il y a un module de noyau mono
installé avec mono
qui intercepte le syscall/s exec
ou intercepte les binaires commençant par 4D 5A
, mais lsmod | grep mono
et amis renvoient une erreur.
Que se passe-t-il ici, et comment le noyau sait-il que cet exécutable est spécial?
Juste pour preuve ce n'est pas ma magie de travail du Shell, j'ai utilisé le Crap Shell (aka sh
) pour exécutez-le et il fonctionne toujours en mode natif.
Voici le programme complet, car un commentateur était curieux:
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");
}
}
C'est binfmt_misc en action: cela permet au noyau de savoir comment exécuter les binaires qu'il ne connaît pas. Regardez le contenu de /proc/sys/fs/binfmt_misc
; parmi les fichiers que vous y voyez, il faut expliquer comment exécuter les binaires mono:
enabled
interpreter /usr/lib/binfmt-support/run-detectors
flags:
offset 0
magic 4d5a
(sur un système Debian). Cela indique au noyau que les binaires commençant par MZ
(4d5a
) doit être donné à run-detectors
. Ce dernier détermine s'il faut utiliser Mono ou Wine pour exécuter le binaire.
Les types binaires peuvent être ajoutés, supprimés, activés et désactivés à tout moment; voir la documentation ci-dessus pour plus de détails (la sémantique est surprenante, le système de fichiers virtuel utilisé ici ne se comporte pas entièrement comme un système de fichiers standard). /proc/sys/fs/binfmt_misc/status
donne le statut global, et chaque "descripteur" binaire montre son statut individuel. Une autre façon de désactiver binfmt_misc
est de décharger son module noyau, s'il est construit en tant que module; cela signifie également qu'il est possible de le mettre sur liste noire pour l'éviter complètement.
Cette fonctionnalité permet de prendre en charge de nouveaux types binaires, tels que les exécutables MZ (qui incluent les binaires Windows PE et PE +, mais aussi les binaires DOS et OS/2!), Java Java ... Il permet également de prendre en charge les types binaires connus sur de nouvelles architectures, généralement en utilisant Qemu; ainsi, avec les bibliothèques appropriées, vous pouvez exécuter en toute transparence ARM binaires Linux sur un processeur Intel!
Votre question découle d'une compilation croisée, bien que dans le sens .NET, et qui soulève une mise en garde avec binfmt_misc
: certains scripts de configuration se comportent mal lorsque vous essayez d'effectuer une compilation croisée sur un système qui peut exécuter les binaires compilés de manière croisée. En règle générale, la détection de la compilation croisée implique la création d'un binaire et la tentative d'exécution. s'il s'exécute, vous ne faites pas de compilation croisée, sinon, vous l'êtes (ou votre compilateur est cassé). autoconf
les scripts peuvent généralement être corrigés dans ce cas en spécifiant explicitement les architectures de build et d'hôte, mais parfois vous devrez désactiver binfmt_misc
temporairement ...