How is Mono magical?
This is binfmt_misc in action: it allows the kernel to be told how to run binaries it doesn't know about. Look at the contents of /proc/sys/fs/binfmt_misc
; among the files you see there, one should explain how to run Mono binaries:
enabled
interpreter /usr/lib/binfmt-support/run-detectors
flags:
offset 0
magic 4d5a
(on a Debian system). This tells the kernel that binaries starting with MZ
(4d5a
) should be given to run-detectors
. The latter figures out whether to use Mono or Wine to run the binary.
Binary types can be added, removed, enabled and disabled at any time; see the documentation above for details (the semantics are surprising, the virtual filesystem used here doesn't behave entirely like a standard filesystem). /proc/sys/fs/binfmt_misc/status
gives the global status, and each binary "descriptor" shows its individual status. Another way of disabling binfmt_misc
is to unload its kernel module, if it's built as a module; this also means it's possible to blacklist it to avoid it entirely.
This feature allows new binary types to be supported, such as MZ executables (which include Windows PE and PE+ binaries, but also DOS and OS/2 binaries!), Java JAR files... It also allows known binary types to be supported on new architectures, typically using Qemu; thus, with the appropriate libraries, you can transparently run ARM Linux binaries on an Intel processor!
Your question stemmed from cross-compilation, albeit in the .NET sense, and that brings up a caveat with binfmt_misc
: some configuration scripts misbehave when you try to cross-compile on a system which can run the cross-compiled binaries. Typically, detecting cross-compilation involves building a binary and attempting to run it; if it runs, you're not cross-compiling, if it doesn't, you are (or your compiler's broken). autoconf
scripts can usually be fixed in this case by explicitly specifying the build and host architectures, but sometimes you'll have to disable binfmt_misc
temporarily...
Related videos on Youtube
cat
Here's a shout-out to the hero of Stack Exchange! You're the best! I like Go, as a statically typed C-style-OOP systems programming language, but it doesn't have generics, and doesn't encourage functional practices. D encourages functional programming, proper OOP and fixes the problems of C and Go while being a better C++, and more productive / less dumb than Java. While I love Python, it feels too mundane; for everyday tasks I prefer Racket and Factor. /* this bit of chicanery is to prevent me from accidentally dereferencing null pointers you might think it's ugly but would you rather have segfault or slightly ugly code? */ // Just trying to create an array of integers for reference // because I keep forgetting how integers look like. (from here.)
Updated on September 18, 2022Comments
-
cat over 1 year
I'm learning C#, so I made a little C# program that says
Hello, World!
, then compiled it withmono-csc
and ran it withmono
:$ mono-csc Hello.cs $ mono Hello.exe Hello, World!
I noticed that when I hit
TAB
inbash
,Hello.exe
was marked executable. Indeed, it runs by just a shell loading the filename!Hello.exe
is not an ELF file with a funny file extension:$ 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
means it's a Microsoft Windows statically linked executable. Drop it onto a Windows box, and it will (should) run.I have
wine
installed, butwine
, being a compatibility layer for Windows apps, takes about 5x as long to runHello.exe
asmono
and executing it directly do, so it's notwine
that runs it.I'm assuming there's some
mono
kernel module installed withmono
that intercepts theexec
syscall/s, or catches binaries that begin with4D 5A
, butlsmod | grep mono
and friends return an error.What's going on here, and how does the kernel know that this executable is special?
Just for proof it's not my shell working magic, I used the Crap Shell (aka
sh
) to run it and it still runs natively.
Here's the program in full, since a commenter was curious:
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"); } }
-
kuldeep.kamboj about 8 yearsWhile you got answer, But I am little bit confused, If you run the commands like
php hello.php
orpython hello.py
orperl hello.pl
or in case of compiled language like javajava hello
they would also run as their are no executable there but a program read and execute file. However if you run./hello.exe
instead ofmono hello.exe
the I found your question and accepted answer more reasonable (which in case definitely use binfmt-support. -
kuldeep.kamboj about 8 yearsActually what I was saying that any code file (or compiled file ) can be executed via its program in format
program codefile
, in your case program is mono, while my examples includes php, python, perl and java. I suspect if mono allow extension to other than .exe file still executed via code. It should not depend at all on windows as finally this is execute a compiled code. However if your source file have some dependent code like windows only APIs then obviously you must need wine for running that exe file. -
kuldeep.kamboj about 8 yearsHowever I checkout this code and able to run by using
./hello.exe
which is without defining program and require it be executable, So there must be role of binfmt_misc to mark it as executable by mono. -
Admin about 8 yearsPart of the wonderful irony of this is that
/etc/magic
or/usr/share/file/magic
(or similar magical location) is the file that contains the information necessary to be able to do this. -
cat about 8 years@MichaelT I thought
magic
was just identifying native file types like media, I never realised it did interesting stuff like this :) -
Admin about 8 years@cat its a very interesting file (if I was to have a favorite file, it would probably be my first choice). It has the information for identifying all sorts of files. But you need to identify what the file is first before you can figure out how to run it. That's what file and its magic does. A similar thing - Java Binary Kernel Support for Linux from awhile back so you could do
$ foo.jar
rather than$ java -jar foo.jar
- similar to what is done for mono. -
Stephen Kitt about 8 yearsJust to clarify,
binfmt_misc
doesn't usemagic
, but as long as the magic bytes are within the first 128 you can use the information given in the magic files to write abinfmt_misc
descriptor. If you want to find out more about magic files, look atlibmagic
. -
rackandboneman about 8 yearsBTW, even ELF files usually specify their own interpreter in a way... that interpreter being the system's dynamic linker.
-
asmeurer about 8 yearsIs Crap Shell a thing now?
-
cat about 8 years@asmeurer ya it is (8
-
-
user about 8 yearsTo those who are curious about /proc, you may be interested in How does /proc/* work? on Super User.