Bash

Linux 是如何載入這個用 C# 編譯的 exe 的?

  • August 14, 2020

我剛剛發現了一件非常令人驚訝的事情。

csc我可以使用(來自 Visual Studio)在我的 Windows 電腦上編譯一個簡單的 C# hello world ,將生成的exe文件複製到我的 Linux 電腦,然後使用mono helloworld.exe. 到目前為止,一切對我來說都是有意義的:根據這篇 SO 文章,在 Windows 上,helloworld.exe基本上只是一個最終啟動 C# 執行時的技巧,而 CIL 字節碼只是稍後從exe文件中的某些數據部分讀取。同樣,我想,在 Linux 上,這樣做mono helloworld.exe只是啟動 C# 執行時並直接讀取字節碼,而不用擔心 exe 詭計。

對於後代,這是我從Charles Petzold 的優秀免費 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 文件而不是 Windows 的 PE 格式。取而代之的是,系統似乎以某種方式足夠聰明,可以開始尋找 wine(在strace輸出中,您可以看到它開始尋找 wine 庫,並且因為我已經在我的 Linux 機器上安裝了 wine,它最終會在稍後找到它們上)。

發生什麼了?如果檢測到 PE 文件,呼叫是否execve足夠聰明,可以嘗試使用 wine,或者這bash是在做什麼?還是完全不同的東西?

你肯定已經通過包管理器安裝了 Wine 或/和 Mono,以及一個特殊的配置文件,它告訴核心一旦使用者啟動一個 exe 文件該做什麼。

更多資訊在這裡:https ://en.wikipedia.org/wiki/Binfmt_misc

引用自:https://unix.stackexchange.com/questions/604539