Как моно волшебно?

149

Я изучаю C #, поэтому я создал небольшую программу на C #, которая говорит Hello, World!, затем скомпилировал ее mono-cscи запустил mono:

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

Я заметил , что когда я попал TABв bash, Hello.exeбыл отмечен исполняемым. Действительно, он запускается только оболочкой, загружающей имя файла!

Hello.exeэто не файл ELF с забавным расширением файла:

$ 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означает, что это статически связанный исполняемый файл Microsoft Windows. Положите его на коробку Windows, и он будет (должен) работать.

Я wineустановил, но wine, будучи уровень совместимости для приложений Windows, занимает около 5х до тех пор , запускать , Hello.exeкак monoи выполнение его непосредственно делать, так что это не wineчто запускает его.

Я предполагаю, что установлен какой-то monoмодуль ядра, monoкоторый перехватывает execсистемный вызов / s или перехватывает двоичные файлы, которые начинаются с 4D 5A, но lsmod | grep monoдрузья возвращают ошибку.

Что здесь происходит, и как ядро ​​узнает, что этот исполняемый файл особенный?


Просто для доказательства , что это не моя оболочка работает магия, я использовал гречиху Shell (он же sh) , чтобы запустить его и он все еще работает изначально.


Вот программа полностью, так как комментатор был любопытен:

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");
  }
}
кошка
источник
4
Пока вы получили ответ, но я немного запутался, если вы запускаете команды, такие как php hello.phpили python hello.pyили, perl hello.plили в случае скомпилированного языка, такого как java, java helloони также будут запускаться, так как они там не исполняемые, а программа чтения и выполнения файла. Однако, если вы запустите ./hello.exeвместо того, mono hello.exeчтобы я нашел ваш вопрос и принял более разумный ответ (который в случае обязательно использовать binfmt-support.
kuldeep.kamboj
@ kuldeep.kamboj Я не уверен, что понимаю то, что вы говорите, но я был просто удивлен, что исполняемый файл Windows работает "изначально" на компьютере с Linux.
кот
1
На самом деле то, что я говорил, что любой файл кода (или скомпилированный файл) может быть выполнен через его программу в формате program codefile, в вашем случае программа моно, в то время как мои примеры включают php, python, perl и java. Я подозреваю, если моно разрешить расширение, отличное от .exe файла, все еще выполняется с помощью кода. Он вообще не должен зависеть от окон, так как, наконец, это выполнение скомпилированного кода. Однако, если ваш исходный файл имеет некоторый зависимый код, такой как API только для Windows, тогда, очевидно, вам нужно Wine для запуска этого exe-файла.
kuldeep.kamboj
4
Часть удивительной иронии этого в том, что /etc/magicили /usr/share/file/magic(или подобное магическое место) - это файл, который содержит информацию, необходимую для того, чтобы это сделать.
1
@cat - это очень интересный файл (если бы у меня был любимый файл, он, вероятно, был бы моим первым выбором). Он имеет информацию для идентификации всех видов файлов. Но вам нужно определить, что это за файл, прежде чем вы сможете понять, как его запустить. Вот что делает файл и его магия. Подобная вещь - Java Binary Kernel Support для Linux с недавних пор, так что вы можете сделать, $ foo.jarа не $ java -jar foo.jar- похоже на то, что делается для моно.

Ответы:

183

Это binfmt_misc в действии: он позволяет ядру сказать, как запускать двоичные файлы, о которых он не знает. Посмотрите на содержимое /proc/sys/fs/binfmt_misc; среди файлов, которые вы там видите, нужно объяснить, как запускать Mono binaries:

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

(в системе Debian). Это говорит ядру, что двоичные файлы, начинающиеся с MZ( 4d5a), должны быть переданы run-detectors. Последний выясняет, использовать ли Mono или Wine для запуска двоичного файла.

Двоичные типы могут быть добавлены, удалены, включены и отключены в любое время; подробности смотрите в документации выше (семантика удивительна, используемая здесь виртуальная файловая система не ведет себя полностью как стандартная файловая система). /proc/sys/fs/binfmt_misc/statusдает глобальный статус, и каждый двоичный «дескриптор» показывает свой индивидуальный статус. Другой способ отключения binfmt_misc- выгрузить модуль ядра, если он собран как модуль; это также означает, что можно занести его в черный список, чтобы полностью избежать.

Эта функция позволяет поддерживать новые двоичные типы, такие как исполняемые файлы MZ (включая двоичные файлы Windows PE и PE +, а также двоичные файлы DOS и OS / 2!), Файлы JAR Java ... Она также позволяет поддерживать известные двоичные типы на новые архитектуры, обычно использующие Qemu; таким образом, с соответствующими библиотеками вы можете прозрачно запускать двоичные файлы ARM Linux на процессоре Intel!

Ваш вопрос возник из-за кросс-компиляции, хотя и в смысле .NET, и это вызывает оговорку binfmt_misc: некоторые скрипты конфигурации ведут себя неправильно, когда вы пытаетесь кросс-компилировать в системе, которая может запускать кросс-компилированные двоичные файлы. Как правило, обнаружение кросс-компиляции включает сборку двоичного файла и попытку его запуска; если он работает, вы не выполняете кросс-компиляцию, если это не так, то вы (или ваш компилятор не работает). autoconfв этом случае сценарии обычно можно исправить, явно указав архитектуру сборки и хоста, но иногда вам придется binfmt_miscвременно отключить ...

Стивен Китт
источник
2
Тем, кто интересуется / proc, вас может заинтересовать, как работает / proc / *? на Супер пользователя .
CVn