¿Cómo es mono mágico?

149

Estoy aprendiendo C #, así que hice un pequeño programa de C # que dice Hello, World!, luego lo compilé mono-cscy lo ejecuté con mono:

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

Me di cuenta de que cuando me golpeó TABen bash, Hello.exefue marcado como ejecutable. De hecho, se ejecuta solo con un shell que carga el nombre del archivo.

Hello.exeno es un archivo ELF con una extensión de archivo divertida:

$ 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..............

MZsignifica que es un ejecutable enlazado estáticamente de Microsoft Windows. Suéltelo en un cuadro de Windows y se ejecutará (debería).

Lo he wineinstalado, pero wine, al ser una capa de compatibilidad para aplicaciones de Windows, tarda aproximadamente 5 veces más en ejecutarse Hello.exeque monoejecutarlo directamente, por lo wineque no es que lo ejecute.

Supongo que hay algún monomódulo de kernel instalado monoque intercepta execsyscall / s, o atrapa binarios que comienzan con 4D 5A, pero lsmod | grep monoy los amigos devuelven un error.

¿Qué está pasando aquí y cómo sabe el núcleo que este ejecutable es especial?


Solo como prueba de que no es mi magia de shell, utilicé Crap Shell (aka sh) para ejecutarlo y todavía se ejecuta de forma nativa.


Aquí está el programa completo, ya que un comentarista tenía curiosidad:

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");
  }
}
gato
fuente
44
Mientras que tienes respuesta, pero estoy poco confundido, si ejecuta los comandos como php hello.phpo python hello.pyo perl hello.plo en caso de lenguaje compilado como Java java hellotambién se ejecutan como su son no ejecutable allí, pero un programa de lectura y ejecución de archivos. Sin embargo, si ejecuta en ./hello.exelugar de mono hello.exela, encontré su pregunta y acepté la respuesta más razonable (que en caso de que definitivamente use binfmt-support.
kuldeep.kamboj
@ kuldeep.kamboj No estoy seguro de entender lo que está diciendo, pero me sorprendió que un ejecutable de Windows se ejecute "de forma nativa" en una caja de Linux.
gato
1
En realidad, lo que estaba diciendo es que cualquier archivo de código (o archivo compilado) se puede ejecutar a través de su programa en formato program codefile, en su caso, el programa es mono, mientras que mis ejemplos incluyen php, python, perl y java. Sospecho que si mono permite la extensión a otro archivo que no sea .exe aún se ejecuta a través del código. No debería depender en absoluto de Windows, ya que finalmente se ejecuta un código compilado. Sin embargo, si su archivo fuente tiene algún código dependiente, como las API de Windows solamente, entonces obviamente debe necesitar wine para ejecutar ese archivo exe.
kuldeep.kamboj
44
Parte de la maravillosa ironía de esto es que /etc/magico /usr/share/file/magic(o una ubicación mágica similar) es el archivo que contiene la información necesaria para poder hacer esto.
1
@cat es un archivo muy interesante (si tuviera que tener un archivo favorito, probablemente sería mi primera opción). Tiene la información para identificar todo tipo de archivos. Pero primero debe identificar cuál es el archivo antes de poder descubrir cómo ejecutarlo. Eso es lo que hace el archivo y su magia. Algo similar: Java Binary Kernel Support para Linux desde hace un tiempo, por lo que podría hacer en $ foo.jarlugar de hacerlo $ java -jar foo.jar, similar a lo que se hace para mono.

Respuestas:

183

Esto es binfmt_misc en acción: permite que se le diga al núcleo cómo ejecutar binarios que no conoce. Mira el contenido de /proc/sys/fs/binfmt_misc; Entre los archivos que ve allí, uno debe explicar cómo ejecutar mono binarios:

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

(en un sistema Debian). Esto le dice al núcleo que los binarios que comienzan con MZ( 4d5a) deben ser dados a run-detectors. Este último determina si usar Mono o Wine para ejecutar el binario.

Los tipos binarios se pueden agregar, eliminar, habilitar y deshabilitar en cualquier momento; Consulte la documentación anterior para obtener más detalles (la semántica es sorprendente, el sistema de archivos virtual utilizado aquí no se comporta completamente como un sistema de archivos estándar). /proc/sys/fs/binfmt_misc/statusda el estado global, y cada "descriptor" binario muestra su estado individual. Otra forma de deshabilitar binfmt_misces descargar su módulo del núcleo, si está construido como un módulo; Esto también significa que es posible ponerlo en la lista negra para evitarlo por completo.

Esta característica permite que se admitan nuevos tipos binarios, como ejecutables MZ (que incluyen binarios de Windows PE y PE +, pero también binarios de DOS y OS / 2), archivos Java JAR ... También permite que se admitan tipos binarios conocidos en nuevas arquitecturas, típicamente usando Qemu; por lo tanto, con las bibliotecas apropiadas, puede ejecutar de forma transparente los binarios ARM Linux en un procesador Intel.

Su pregunta surgió de la compilación cruzada, aunque en el sentido .NET, y eso plantea una advertencia con binfmt_misc: algunos scripts de configuración se comportan mal cuando intenta compilar en un sistema que puede ejecutar los binarios con compilación cruzada. Normalmente, detectar la compilación cruzada implica construir un binario e intentar ejecutarlo; si se ejecuta, no estás compilando de forma cruzada, si no lo hace, lo estás (o tu compilador está roto). autoconfLos scripts generalmente se pueden arreglar en este caso especificando explícitamente las arquitecturas de compilación y host, pero a veces tendrá que deshabilitar binfmt_misctemporalmente ...

Stephen Kitt
fuente
2
Para aquellos que sienten curiosidad por / proc, pueden estar interesados ​​en ¿Cómo funciona / proc / *? en Super Usuario .
un CVn