對於不同架構處理器,不同操作系統,相同編譯器對源碼編譯的結果有什麼不同?

以下問題很傻很亂全程腦洞,希望各位答主能耐著性子和砍死我的心看完,謝謝:

場景一:

比方說我在Linux上用C寫了個程序然後用gcc編譯出來,是個.out 二進位機器碼可執行文件。

然後再在Windows上寫了一個同樣的程序,同樣也是用gcc編譯出來,是個.exe二進位機器碼可執行文件。

以上兩台機子使用同種架構的處理器。

問題1(基於場景一):這兩個可執行文件的機器碼是否相同?

場景二:

還是兩台計算機(暫且叫A計算機和B計算機),搭載同樣的系統(比方說Ubuntu)但這兩台計算機使用了不同架構的CPU(指令集不一樣的兩種CPU),然後同樣分別在兩台計算機上寫了相同的程序,使用相同的編譯器(比如gcc)進行編譯,編譯結果都是得到.out 二進位機器碼可執行文件。

問題2(基於場景二):這兩個可執行文件的機器碼是否相同?

問題3(基於場景二):在A計算機上編譯好的.out文件可以在B計算機上被執行嗎?

問題3.1(基於問題3):不同的操作系統被編譯成機器碼後被儲存在Flash或硬碟里,當機器上電後BIOS會引導處理器執行系統。如果A計算機上編譯好的.out文件可以在B計算機上被執行,那麼為什麼有些不同架構的處理器不可以運行同種操作系統呢(比方說為什麼ARM架構不可以運行Windows XP)?。

問題3.1.1(基於問題3.1):如果問題3.1的答案是不同指令集的機器碼不一樣。現在假設(注意這只是假設!)我現在有Windows XP的完整源代碼,然後我在安裝著ARM架構處理器的計算機上對Windows XP的源代碼進行編譯(這裡不考慮技術難度),那麼編譯完的Windows XP系統可以在使用ARM架構處理器的計算機上運行嗎?


1. 問題本身有問題,機器指令是針對 CPU 而言,顯然都是 x86,那麼機器碼是一樣的。

我感覺你想問的是二進位文件是否相同,那麼答案是當然不同。應用程序有組織的格式,具體到windows就是PE,linux 一般是 ELF,這是組織的方式不一樣。應用程序與操作系統的介面是 系統調用,linux 和 windows 的系統調用是不一樣的,導致了程序的主體內容也不一樣。其他應用程序中純邏輯部分編譯出來可能有部分機器碼片段是相同的。

2. 必然不同

3. 不行

3.1 因為3,問題不存在了

3.1.1 理論上可以,假設windows源碼可移植性非常好,並且缺失的部分驅動代碼你自己有能力補上。

題主的求知慾我很佩服,但是我唐突猜測你可能學習時候貪多求快,導致這些基本的問題沒有搞明白,結果還是要回頭來補課。

技術這件事,慢即是快,沒有捷徑,與你共勉。


*然而不同的操作系統相同的代碼可以直接編譯運行么?

比如說c吧,基本上所有的用c寫的應用程序都會有這句,或者其引用的頭文件有這句:

#include &

那麼stdlib是什麼,為什麼只有stdlib.h而沒有stdlib.c呢

因為stdlib是一個平台特定的鏈接庫,linux下常用glibc,而windows下這玩意叫做vc runtime

所以不同的操作系統下編譯出的二進位區別大發了

*然而操作系統的平台相關的代碼根據不同的平台是不同的,這是一些編譯開關決定的,比如說linux源碼的make config就有平台這個選項,嚴格得說不同平台不可能運行同一個源碼編譯出的內核。

然而既然指令集不一樣,二進位文件怎麼可能可以通用嘛

你這樣naive,要多讀書啊


這麼說吧,現代編譯器絕大多數後端(生成機器代碼的部分)有能力生成多種體系結構的代碼。gcc本身支持多種體系結構包括ARM,只是默認情況編譯為本機架構。編譯器生成代碼可以與本機架構無關。你可以在x86上把代碼編譯成ARM的二進位,也可以在ARM上把代碼編譯成x86的二進位。

接下來:

問題1: 二進位不同。Windows的.exe和Linux的.out文件結構不同。這與機器碼無關。

問題2: 當編譯時目標體系結構相同,源代碼(包括引用的頭文件)相同,編譯器版本號完全相同,輸出參數完全相同時理論上機器碼一樣(但封裝的文件格式不同)。

問題3: 當你在A計算機上編譯為B的體系結構時可以。

問題3.1: 因為操作系統中涉及到I/O指令的必須用彙編完成。彙編文件數量較大(雖然仍不佔5%),編寫複雜,因此在ARM市場沒有Windows XP的需求時微軟不會為其重寫這5%。

問題3.1.1: 你不可能在不改代碼的情況把含有x86彙編的代碼編譯為ARM架構的二進位。因此你無法在不進行大量改動(那5%可能四個人都難以在短時間內改完)的情況下編譯Windows XP。另:(1)Windows很早就有ARM版。參見Windows CE、Windows RT、Windows Mobile和Windows Phone。(2)XP之所以沒有ARM版是因為存在Windows CE且大部分當時的PDA和手機(當時僅有運行Windows的ARM版的設備)內存尚不夠運行XP。


自己用objdump反彙編看看唄


問題1: 機器碼不同。原因至少有二:1.可執行文件中有編譯器的代碼加入(即使不執行系統調用,不使用c庫的任何函數,也無法避免)以及編譯器優化的影響;2. 平台間的ABI可能不同。

問題2:機器碼不同。指令集不一樣的系統上,機器碼很難相同。這個不需要過多解釋了吧?

問題3:不可以。原因:指令集都不一樣,一個理由就足夠了。

問題3.1: 因問題3,該問題不存

問題3.1.1: 不可以。操作系統不是普通程序。如果是普通c代碼,可以跨平台編譯並運行,但操作系統不行。理由如下:

1): 不同的體系結構有不同的硬體特性,例如:cpu的寄存器,內存頁表結構,io讀寫方式等等等等。這些硬體特性對普通程序不可見,但對os是可見的。

2): 基於理由1),os的一些代碼需要由彙編實現,而彙編是不具備有跨體系結構的。在Linux中,進程切換這樣常用的操作都需要針對不同的體系結構單獨編碼。

3): 除非這個操作系統的源碼中已經針對不同的體系結構進行單獨編碼了(例如Linux),否則通過簡單的編譯難以實現跨體系結構(windows xp)。

------------------------------------

另:題主的問題基本上可通過理解API和ABI兩個概念來獲得解答。API兼容解決跨平台編譯問題;而ABI兼容則可以跨平台運行。


推薦閱讀:

Android操作系統還會流行多久?
微軟實現新版本操作系統向下兼容困難嗎?
阿里巴巴沒有能力開發出媲美linux的操作系統嗎?有的話為什麼不開發?
高頻交易中是否需要實時操作系統?

TAG:操作系統 | 嵌入式系統 | 編譯器 | 處理器 |