Как Linux загрузил этот exe-файл, скомпилированный с помощью C#?

Как Linux загрузил этот exe-файл, скомпилированный с помощью C#?

Я только что обнаружил нечто действительно удивительное.

Я могу скомпилировать простой C# hello world на моем компьютере Windows с помощью csc(из Visual Studio), скопировать полученный exeфайл на мой компьютер Linux и выполнить его с помощью mono helloworld.exe. Пока что все имеет смысл для меня: согласноэтот пост ТАК, в Windows, helloworld.exeпо сути, просто трюк, который в итоге запускает среду выполнения C#, а байт-код CIL просто считывается из некоторого раздела данных далее в файле exe. Аналогично, я представляю, что в Linux выполнение mono helloworld.exeпросто запускает среду выполнения C# и напрямую считывает байт-код, не заморачиваясь с трюком с exe.

Для потомков, вот источник, который я взял изПревосходная бесплатная книга Чарльза Петцольда по C#:

//---------------------------------------------
// FirstProgram.cs (c) 2006 by Charles Petzold
//---------------------------------------------
class FirstProgram
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, Microsoft .NET Framework!");
    }
}

Но вот тут-то все становится интереснее: в Linux ( uname -rна моей машине это возможно 4.14.188-1-MANJARO) я могу просто сделать это ./helloworld.exe, и это работает!

Я начал расследование, и вот первые несколько строк из бега strace ./helloworld.exe:

execve("./hw.exe", ["./hw.exe"], 0x7fffae8e6070 /* 61 vars */) = 0
[ Process PID=3381 runs in 32 bit mode. ]
brk(NULL)                               = 0x7eedb000
arch_prctl(0x3001 /* ARCH_??? */, 0xffb19948) = -1 EINVAL (Invalid argument)
readlink("/proc/self/exe", "/usr/bin/wine", 4096) = 13
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7faa000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/bin/../lib32/tls/i686/sse2/libwine.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/../lib32/tls/i686/sse2", 0xffb18e00) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/bin/../lib32/tls/i686/libwine.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/../lib32/tls/i686", 0xffb18e00) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/bin/../lib32/tls/sse2/libwine.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/../lib32/tls/sse2", 0xffb18e00) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/bin/../lib32/tls/libwine.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/../lib32/tls", 0xffb18e00) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/bin/../lib32/i686/sse2/libwine.so.1", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/../lib32/i686/sse2", 0xffb18e00) = -1 ENOENT (No such file or directory)

Я бы ожидал какой-то ошибки, говорящей "этот файл не является допустимым исполняемым файлом", так как я ожидаю, что загрузчик программ Linux будет понимать только файлы ELF, а не формат PE Windows. Вместо этого, похоже, система каким-то образом достаточно умна, чтобы начать искать wine (в выводе straceвы можете видеть, что она начинает искать библиотеки wine, и поскольку я установил wine на своей машине Linux, она в конечном итоге находит их позже).

Так что же происходит? execveДостаточно ли умен вызов, чтобы попытаться использовать wine, если он обнаружит PE-файл, или это что-то, что bashделает? Или это что-то совсем другое?

решение1

У вас наверняка установлены Wine и/или Mono через менеджер пакетов, а также специальный файл конфигурации, который сообщает ядру, что делать, когда пользователь запускает exe-файл.

Подробнее об этом здесь:https://en.wikipedia.org/wiki/Binfmt_misc

Связанный контент