Como é Mono mágico?

149

Estou aprendendo c #, então fiz um pequeno programa em c # que diz Hello, World!, compilei mono-csce executei com mono:

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

Notei que quando eu bati TABem bash, Hello.exefoi marcado executável. Na verdade, ele roda apenas por um shell que carrega o nome do arquivo!

Hello.exenão é um arquivo ELF com uma extensão de arquivo engraçada:

$ 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 é um executável estaticamente vinculado do Microsoft Windows. Solte-o em uma caixa do Windows e ele (deve) ser executado.

Tenho wineinstalado, mas wine, sendo uma camada de compatibilidade para aplicativos Windows, leva cerca de 5x mais tempo para executar Hello.execomo monoe executá-lo diretamente que, portanto, não é wineque vai.

Eu estou assumindo que há algum monomódulo do kernel instalado com monoque intercepta o execsyscall / s ou captura binários que começam com 4D 5A, mas os lsmod | grep monoamigos retornam um erro.

O que está acontecendo aqui e como o kernel sabe que esse executável é especial?


Só para provar que não é a minha mágica de trabalho do shell, usei o Crap Shell (aka sh) para executá-lo e ele ainda é executado de forma nativa.


Aqui está o programa na íntegra, uma vez que um comentarista estava 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");
  }
}
gato
fonte
4
Enquanto você recebe a resposta, mas estou um pouco confuso, se você executar os comandos como php hello.phpou python hello.pyou perl hello.plou no caso de linguagem compilada como java, java helloeles também serão executados, pois não são executáveis ​​lá, mas um programa lê e executa o arquivo. No entanto, se você executar ./hello.exeem vez mono hello.exedo que eu encontrei sua pergunta e resposta aceita mais razoável (que no caso definitivamente usar binfmt-apoio.
kuldeep.kamboj
@ kuldeep.kamboj Não sei ao certo o que você está dizendo, mas fiquei surpreso ao ver que um executável do Windows roda "nativamente" em uma caixa do Linux.
gato
1
Na verdade, o que eu estava dizendo é que qualquer arquivo de código (ou arquivo compilado) pode ser executado por meio do programa em formato program codefile, no seu caso o programa é mono, enquanto meus exemplos incluem php, python, perl e java. Eu suspeito que se mono permitir extensão para outro arquivo que não seja .exe ainda executado via código. Não deve depender absolutamente do Windows, pois, finalmente, este é um código compilado. No entanto, se o seu arquivo de origem tiver algum código dependente, como APIs apenas do Windows, obviamente você precisará do wine para executar esse arquivo exe.
precisa saber é o seguinte
4
Parte da maravilhosa ironia disso é que /etc/magicou /usr/share/file/magic(ou local mágico semelhante) é o arquivo que contém as informações necessárias para poder fazer isso.
1
@cat é um arquivo muito interessante (se eu tivesse um arquivo favorito, provavelmente seria minha primeira escolha). Ele possui as informações para identificar todos os tipos de arquivos. Mas você precisa identificar qual é o primeiro arquivo antes de descobrir como executá-lo. É isso que arquivo e sua mágica fazem. Uma coisa semelhante - o Suporte ao Kernel Binário Java para Linux há algum tempo, para que você possa fazer um $ foo.jarpouco do que $ java -jar foo.jar- semelhante ao que é feito para mono.

Respostas:

183

Isso é binfmt_misc em ação: permite que o kernel seja informado sobre como executar binários que não conhece. Veja o conteúdo de /proc/sys/fs/binfmt_misc; Entre os arquivos que você vê lá, deve-se explicar como executar os binários Mono:

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

(em um sistema Debian). Isso informa ao kernel que os binários iniciados com MZ( 4d5a) devem ser fornecidos run-detectors. O último calcula se o Mono ou o Wine deve ser executado para executar o binário.

Tipos binários podem ser adicionados, removidos, ativados e desativados a qualquer momento; veja a documentação acima para obter detalhes (a semântica é surpreendente, o sistema de arquivos virtual usado aqui não se comporta inteiramente como um sistema de arquivos padrão). /proc/sys/fs/binfmt_misc/statusfornece o status global e cada "descritor" binário mostra seu status individual. Outra maneira de desativar binfmt_miscé descarregar seu módulo do kernel, se ele for construído como um módulo; isso também significa que é possível colocá-lo na lista negra para evitá-lo completamente.

Esse recurso permite que novos tipos binários sejam suportados, como executáveis ​​MZ (que incluem binários Windows PE e PE +, mas também binários DOS e OS / 2!), Arquivos Java JAR ... Também permite que tipos binários conhecidos sejam suportados em novas arquiteturas, normalmente usando o Qemu; portanto, com as bibliotecas apropriadas, você pode executar de forma transparente os binários do ARM Linux em um processador Intel!

Sua pergunta surgiu da compilação cruzada, embora no sentido .NET, e isso traz uma ressalva binfmt_misc: alguns scripts de configuração se comportam mal quando você tenta compilar em um sistema que pode executar os binários compilados. Normalmente, a detecção da compilação cruzada envolve a construção de um binário e a tentativa de executá-lo; se for executado, você não fará a compilação cruzada; caso contrário, estará (ou o seu compilador está quebrado). autoconfGeralmente, os scripts podem ser corrigidos nesse caso, especificando explicitamente as arquiteturas de compilação e host, mas às vezes você precisará desativar binfmt_misctemporariamente ...

Stephen Kitt
fonte
2
Para aqueles que estão curiosos sobre / proc, você pode estar interessado em Como funciona o / proc / *? no Superusuário .
um CVn 05/02