web-dev-qa-db-ja.com

Monoはどのように魔法ですか?

私はC#を学んでいるので、Hello, World!と言う小さなC#プログラムを作成し、mono-cscを使用してコンパイルし、monoを使用して実行しました。

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

TABbashを押すと、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アプリの互換性レイヤーであるため、Hello.exemonoとして実行するのに約5倍の時間がかかり、直接実行しますなので、実行するのはwineではありません。

mono syscall/sをインターセプトする、または4D 5Aで始まるバイナリをキャッチするmonoとともにインストールされているexecカーネルモジュールがあると仮定していますが、lsmod | grep monoと友達はエラーを返します。

ここで何が起こっているのですか、そしてカーネルはthis実行可能ファイルが特別であることをどのようにして知っていますか?


証明のためだけではありませんmyシェルの動作魔法、私は The Crap Shell (aka 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");
  }
}
153
cat

これは binfmt_misc の動作です。これにより、カーネルは、知らないバイナリを実行する方法を知ることができます。 _/proc/sys/fs/binfmt_misc_の内容を見てください。そこにあるファイルの中で、Monoバイナリの実行方法を説明する必要があります。

_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_を無効にするもう1つの方法は、モジュールとして構築されている場合、カーネルモジュールをアンロードすることです。これは、完全に回避するためにブラックリストに登録することが可能であることも意味します。

この機能により、MZ実行可能ファイル(Windows PEおよびPE +バイナリだけでなく、DOSおよびOS/2バイナリも含まれます)などの新しいバイナリタイプをサポートできます。Java JARファイル...また、既知のバイナリタイプを新しいアーキテクチャでサポートできるようになり、通常はQemuを使用するため、適切なライブラリを使用して、IntelプロセッサでARM Linuxバイナリを透過的に実行できます。

あなたの質問は、.NETの意味ではありますが、クロスコンパイルから生じたもので、_binfmt_misc_に関する警告が表示されます。クロスコンパイルされたバイナリを実行できるシステムでクロスコンパイルしようとすると、一部の構成スクリプトが正しく動作しません。通常、クロスコンパイルの検出には、バイナリの構築と実行の試行が含まれます。実行された場合、クロスコンパイルは行われず、実行されなかった場合(またはコンパイラが壊れています)。この場合、autoconfスクリプトは通常、ビルドアーキテクチャとホストアーキテクチャを明示的に指定することで修正できますが、_binfmt_misc_を一時的に無効にする必要がある場合があります...

189
Stephen Kitt