Comment Mono est magique?

149

J'apprends le C #, alors j'ai créé un petit programme C # qui dit Hello, World!, puis je l'ai compilé mono-cscet exécuté avec mono:

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

J'ai remarqué que quand je frappe TABdans bash, Hello.exea été marqué exécutable. En effet, il ne fonctionne que par un shell chargeant le nom du fichier!

Hello.exen'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..............

MZsignifie que c'est un exécutable lié statiquement à Microsoft Windows. Déposez-le sur une fenêtre Windows, et il sera (devrait) s'exécuter.

J'ai wineinstallé, mais wine, étant une couche de compatibilité pour les applications Windows, il faut environ 5 fois plus de temps pour s'exécuter en Hello.exetant qu'exécutant monodirectement. Par conséquent, ce n'est pas lui winequi l'exécute.

Je suppose qu'un monomodule de noyau installé monointercepte le exec/ les appels système, ou capture les fichiers binaires commençant par 4D 5A, mais lsmod | grep monoque les amis retournent une erreur.

Que se passe-t-il ici et comment le noyau sait-il que cet exécutable est spécial?


Juste pour prouver que ce n’est pas ma magie qui fonctionne, j’ai utilisé le Crap Shell (alias sh) pour l’exécuter et il fonctionne toujours en mode natif.


Voici le programme complet, puisqu'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");
  }
}
chat
la source
4
Bien que vous ayez la réponse, mais je suis un peu confus, si vous exécutez les commandes telles que php hello.phpou python hello.pyou perl hello.plou dans le cas d’un langage compilé tel que java, java helloelles s’exécuteraient également car elles ne sont exécutables, mais un programme lit et exécute un fichier. Cependant, si vous courez à la ./hello.exeplace de mono hello.exela, j'ai trouvé votre question et votre réponse plus raisonnables (ce qui, dans le cas contraire, utilise définitivement binfmt-support.
kuldeep.kamboj
@ kuldeep.kamboj Je ne suis pas sûr de comprendre ce que vous dites, mais j'ai été surpris qu'un exécutable Windows s'exécute "de manière native" sur une machine Linux.
chat
1
En fait, ce que je disais, c'est que n'importe quel fichier de code (ou fichier compilé) peut être exécuté via son programme au format program codefile. Dans votre cas, le programme est mono, alors que mes exemples incluent php, python, perl et java. Je soupçonne que si mono autoriser l'extension à un fichier autre que .exe toujours exécuté via le code. Cela ne devrait pas dépendre du tout de Windows, car il s'agit finalement d'exécuter un code compilé. Cependant, si votre fichier source a un code dépendant, tel que des API Windows uniquement, il est évident que vous devez avoir besoin de wine pour exécuter ce fichier exe.
kuldeep.kamboj
4
Une partie de la merveilleuse ironie de cela est que /etc/magicou /usr/share/file/magic(ou un endroit magique similaire) est le fichier qui contient les informations nécessaires pour pouvoir le faire.
1
@cat c'est un fichier très intéressant (si j'avais un fichier favori, ce serait probablement mon premier choix). Il a les informations pour identifier toutes sortes de fichiers. Mais vous devez d'abord identifier le fichier avant de savoir comment l'exécuter. C'est ce que fait le fichier et sa magie. Une chose similaire - le support du noyau binaire Java pour Linux depuis un certain temps afin que vous puissiez le faire $ foo.jarplutôt que $ java -jar foo.jar- similaire à ce qui est fait pour le mono.

Réponses:

183

C'est binfmt_misc en action: cela permet au noyau de savoir comment exécuter des fichiers binaires qu'il ne connaît pas. Regardez le contenu de /proc/sys/fs/binfmt_misc; parmi les fichiers que vous voyez ici, il faut expliquer comment exécuter les fichiers 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 fichiers binaires commençant par MZ( 4d5a) doivent être donnés à 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/statusdonne le statut global et chaque "descripteur" binaire montre son statut individuel. Une autre façon de désactiver binfmt_miscconsiste à décharger son module de noyau, s'il est construit en tant que module; cela signifie également qu'il est possible de le mettre sur une 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!), Les fichiers JAR Java ... Elle permet également la prise en charge des types binaires connus nouvelles architectures, utilisant généralement Qemu; ainsi, avec les bibliothèques appropriées, vous pouvez exécuter de manière transparente des fichiers binaires ARM Linux sur un processeur Intel!

Votre question découle de la compilation croisée, bien qu'au sens .NET, ce qui soulève un avertissement binfmt_misc: certains scripts de configuration se comportent mal lorsque vous essayez de compiler sur un système capable d'exécuter les fichiers binaires compilés. En règle générale, la détection de la compilation croisée implique la création d'un fichier binaire et sa tentative d'exécution. si ça marche, vous n'êtes pas cross-compilation, sinon, vous êtes (ou votre compilateur est en panne). autoconfles scripts peuvent généralement être corrigés dans ce cas en spécifiant explicitement les architectures de construction et d'hôte, mais vous devrez parfois désactiver binfmt_misctemporairement ...

Stephen Kitt
la source
2
Pour ceux qui sont curieux de / proc, vous pouvez être intéressé par Comment fonctionne / proc / *? sur super utilisateur .
un CVn