Linux 是如何載入這個用 C# 編譯的 exe 的?
我剛剛發現了一件非常令人驚訝的事情。
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 文件該做什麼。