Como o Mono é mágico?

145

Estou aprendendo C #, então fiz um pequeno programa C # que diz Hello, World! , depois compilei com mono-csc e executei com mono :

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

Percebi que, quando atingi TAB em bash , Hello.exe estava marcado como executável. Na verdade, ele é executado apenas por um shell carregando o nome do arquivo!

Hello.exe is nã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..............

MZ significa que é um executável vinculado estaticamente ao Microsoft Windows. Solte-o em uma caixa do Windows e ele deverá (deve) ser executado.

Eu tenho wine instalado, mas wine , sendo uma camada de compatibilidade para aplicativos do Windows, demora cerca de 5x para executar Hello.exe como mono e executá-lo diretamente, portanto, não é wine executa-o.

Suponho que há um módulo do kernel mono instalado com mono que intercepta exec syscall / s ou captura binários que começam com 4D 5A , mas lsmod | grep mono e amigos retornam um erro.

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

Só para provas, não é a mágica my da shell, eu usei o the Crap Shell ( aka sh ) para executá-lo e ainda é executado nativamente.

Aqui está o programa na íntegra, já que um comentarista ficou 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");
  }
}
    
por cat 02.02.2016 / 18:17

1 resposta

180

Isso é binfmt_misc em ação: ele permite que o kernel seja ser informado sobre como executar binários que ele 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 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 que começam com MZ ( 4d5a ) devem ser fornecidos para run-detectors . Este último descobre se deve usar Mono ou Wine para executar o binário.

Tipos binários podem ser adicionados, removidos, ativados e desativados a qualquer momento; veja a documentação acima para 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/status fornece o status global e cada "descritor" binário mostra seu status individual. Outra maneira de desabilitar binfmt_misc é descarregar seu módulo do kernel, se ele for construído como um módulo; isso também significa que é possível fazer uma lista negra para evitá-lo completamente.

Esse recurso permite que novos tipos binários sejam suportados, como executáveis MZ (que incluem binários do Windows PE e PE +, mas também binários DOS e OS / 2!), arquivos Java JAR ... Ele também permite que tipos binários conhecidos sejam ser suportado em novas arquiteturas, geralmente usando o Qemu; Assim, com as bibliotecas apropriadas, você pode executar transparentemente binários do ARM Linux em um processador Intel!

Sua pergunta surgiu da compilação cruzada, embora no sentido do .NET, e isso traz uma ressalva com binfmt_misc : alguns scripts de configuração se comportam mal quando você tenta compilar em um sistema que pode executar o cross-compilado binários. Normalmente, detectar a compilação cruzada envolve a construção de um binário e a tentativa de executá-lo; se ele for executado, você não está compilando, se não estiver, você está (ou o seu compilador está quebrado). Os scripts autoconf geralmente podem ser corrigidos neste caso especificando explicitamente as arquiteturas de construção e de host, mas às vezes você terá que desativar binfmt_misc temporariamente ...

    
por 02.02.2016 / 18:26