
Acabei de descobrir algo realmente surpreendente.
Posso compilar um hello world C# simples em meu computador Windows usando csc
(do Visual Studio), copiar o exe
arquivo resultante para meu computador Linux e executá-lo com mono helloworld.exe
. Até agora, tudo faz sentido para mim: de acordo comesta postagem SO, no Windows, helloworld.exe
é basicamente apenas um truque que acaba iniciando o tempo de execução do C#, e o bytecode CIL é lido apenas em alguma seção de dados posteriormente no exe
arquivo. Da mesma forma, imagino que, no Linux, fazer mono helloworld.exe
apenas inicia o tempo de execução do C# e lê diretamente o bytecode sem se preocupar com os truques do exe.
Para a posteridade, aqui está a fonte, que obtive deExcelente livro gratuito de C# de Charles Petzold:
//---------------------------------------------
// FirstProgram.cs (c) 2006 by Charles Petzold
//---------------------------------------------
class FirstProgram
{
public static void Main()
{
System.Console.WriteLine("Hello, Microsoft .NET Framework!");
}
}
Mas é aqui que a coisa fica interessante: no Linux ( uname -r
na minha máquina dá 4.14.188-1-MANJARO
) eu posso simplesmente fazer ./helloworld.exe
e funciona!
Comecei a fazer algumas investigações e aqui estão as primeiras linhas da execução 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)
Eu esperava algum erro dizendo "este arquivo não é um executável válido", já que só espero que o carregador de programas do Linux entenda arquivos ELF em vez do formato PE do Windows. Em vez disso, parece que de alguma forma o sistema é inteligente o suficiente para começar a procurar por wine (na strace
saída, você pode ver que ele começa a procurar por bibliotecas de wine e, como instalei o wine em minha máquina Linux, ele eventualmente as encontra mais tarde sobre).
Então o que está acontecendo? A execve
chamada é inteligente o suficiente para tentar usar o wine se detectar um arquivo PE ou isso é algo que bash
está acontecendo? Ou é algo totalmente diferente?
Responder1
Definitivamente, você tem o Wine ou/ou o Mono instalado por meio de um gerenciador de pacotes e junto com ele um arquivo de configuração especial que informa ao kernel o que fazer quando o usuário iniciar um arquivo exe.
Mais sobre isso aqui:https://en.wikipedia.org/wiki/Binfmt_misc