導航:首頁 > 源碼編譯 > 編譯順序不同二進制不同

編譯順序不同二進制不同

發布時間:2023-01-12 20:51:26

㈠ 不同的編譯器生成的二進制文件不同嗎

是 一樣 的

㈡ 編譯器生成的匯編語句執行順序為什麼與C代碼順序不同

不影響語義的前提下編譯器可以任意重排代碼順序;
在亂序執行(Out-of-Order)的CPU里,機器碼的執行也可以不按照你在「匯編」層面上看到的順序執行,只要不影響語義。
所以說這些中間步驟的順序,作為底層細節平時不需要那麼在意——它們多半跟原始源碼的順序是不一樣的。

現代優化編譯器優化的思路之一是「基於依賴的優化」(dependence-based optimization)。題主引用的CSAPP的例子:

int arith(int x, int y, int z) {
int t1 = x + y;
int t2 = z * 48;
int t3 = t1 & 0xFFFF;
int t4 = t2 * t3;
return t4;
}

所有涉及運算的值都是局部標量變數(local scalar variable),這是最便於編譯器做分析的情況,所有依賴都可以顯式分析。
由於整個函數沒有分支,這里也不需要討論控制依賴(control dependence),只要討論數據依賴(data dependence)就好。
把數據依賴圖畫出來是個DAG(這里正好是棵樹,特例了):

x y z 48
\ / \ /
t1 0xFFFF t2
\ / /
t3 /
\ /
t4

優化必須要滿足的約束是:每個節點求值之前,其子節點(依賴的數據源)必須要先求了值。
顯然,t1和t2之間沒有依賴關系,它們的相對求值順序怎樣重排都沒關系。

有本我很喜歡的書,裡面講的是各種基於依賴的優化:Optimizing Compilers for Modern Architectures - A Dependence-based Approach

以上是理論部分。

================================================================

下面來看例子。

我們可以用一個實際編譯器來看看CSAPP的例子編譯出來的結果:

.text
# -- Begin arith
.p2align 4,,15
.globl arith
.type arith, @function
arith:
.p2align 4,,7
/*.L0:*/ /* Block BB[54:2] preds: none, freq: 1.000 */
movl 8(%esp), %edx /* ia32_Load T[139:10] -:1:22 */
addl 4(%esp), %edx /* ia32_Add Iu[141:12] -:2:14 */
movzwl %dx, %edx /* ia32_Conv_I2I Iu[142:13] -:4:15 */
imull 12(%esp), %edx /* ia32_IMul Iu[143:14] -:5:15 */
leal (%edx,%edx,2), %eax /* ia32_Lea Iu[144:15] -:5:15 */
shll $0x4, %eax /* ia32_Shl Iu[146:17] -:5:15 */
ret /* ia32_Return X[152:23] -:6:3 */
.size arith, .-arith
# -- End arith

這里用的是libFirm。可見它跟CSAPP書里所說的匯編的順序又有所不同。這也是完全合理的。
這個編譯結果的順序是:

edx = y;
edx += x;
edx = zeroextend dx; // edx = edx & 0xFFFF
edx *= z;
eax = edx * 3;
eax <<= 4; // eax = eax * 16

也是完全符合依賴關系的約束的一種順序。
之所以用libFirm舉例是因為它的中間表示(Intermediate Representation)是一種程序依賴圖(Program Dependence Graph),可以很方便的看出控制與數據依賴。把CSAPP那裡例子對應的libFirm IR畫出來,是這個樣子的:
(這張圖跟我前面畫的數據依賴圖正好是左右翻轉的,不過意思一樣。(這張圖跟我前面畫的數據依賴圖正好是左右翻轉的,不過意思一樣。
Arg 0、1、2分別代表x、y、z。白色方塊是普通數據節點,黃色方塊是常量節點,藍色方塊是內存相關節點,紅色方塊是控制流節點,粉紅色方塊是特殊的開始/結束節點。)

某版LLVM生成的代碼:

; MoleID = '/tmp/webcompile/_16355_0.bc'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-ellcc-linux"

; Function Attrs: nounwind readnone
define i32 @arith(i32 %x, i32 %y, i32 %z) #0 {
entry:
%add = add nsw i32 %y, %x
%mul = mul nsw i32 %z, 48
%and = and i32 %add, 65535
%mul1 = mul nsw i32 %mul, %and
ret i32 %mul1
}

attributes #0 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"ecc 0.1.10 based on clang version 3.7.0 (trunk) (based on LLVM 3.7.0svn)"}

最終生成的x86匯編:

.text
.file "/tmp/webcompile/_15964_0.c"
.globl arith
.align 16, 0x90
.type arith,@function
arith: # @arith
# BB#0: # %entry
movl 8(%esp), %eax
addl 4(%esp), %eax
movzwl %ax, %eax
imull 12(%esp), %eax
shll $4, %eax
leal (%eax,%eax,2), %eax
retl
.Ltmp0:
.size arith, .Ltmp0-arith

.ident "ecc 0.1.10 based on clang version 3.7.0 (trunk) (based on LLVM 3.7.0svn)"
.section ".note.GNU-stack","",@progbits

GCC 4.9.2 x86-64:

arith(int, int, int):
leal (%rdx,%rdx,2), %eax
addl %edi, %esi
movzwl %si, %esi
sall $4, %eax
imull %esi, %eax
ret

Zing VM Server Compiler x86-64:

# edi: x
# esi: y
# edx: z
movl %edx, %eax
shll $0x4, %eax
leal (%rsi, %rdi, 1), %ecx
shll $0x5, %edx
addl %edx, $eax
movzwl %ecx, %edx
imull %edx, %eax

㈢ linux編譯器的解析順序與windows編譯器的區別

沒區別,都是編譯成obj lib等目標文件和庫文件,然後鏈接為可執行的二進制代碼,Win平台多了一個動態鏈接庫。

㈣ flash 兩次編譯成swf 二進制源碼為什麼不同

flash反編譯後,經過修改還能再次編譯成 swf文件。
反編譯一般用閃客精靈
在更改的過程中,代碼不出錯誤,才能正常編譯成功。
在更改過程中,僅僅是修改了文字或者是圖片,一般是能成功編譯的。

㈤ 二進制代碼和二進制數據有什麼不同

樓主混淆了表義和表現兩者
也就是說,代碼和數據的表現都是二進制編碼,但是真正的含義(即用途)是不同的
代碼和數據的編碼都是二進制(計算機中)的,數字本身沒有什麼區別
但是如果一段二進制編碼,從意義層面上來講具備執行能力,那麼就認為是代碼
而如果此二進制編碼,作為數據被讀取並處理,那麼就是數據
舉個簡單的例子就好理解了:
同樣的可執行文件exe:如果交給操作系統的程序載入器,它會解析其中的text段,以執行計算機指令,這部分的二進制編碼從意義上講就是你說的二進制代碼
但是如果exe被病毒讀取,以達到感染的目的,那麼病毒會讀取text段,並有選擇的修改段代碼,這時這部分二進制編碼對病毒來說就是二進制數據了

㈥ 為什麼說,用c語言寫的程序比匯編語言寫的程序執行效率上要低,難道兩者編譯成的二進制代碼有很大不同

匯編可以直接操作硬體,而C語言則對這些底層操作進行了一定程度的封裝,而封裝就意味著執行過程復雜度的增加。所以說,雖然二者最後實現的效果是一樣的,但後者的執行過程要比前者復雜,編譯成的二進制代碼也就有所不同。

㈦ 自已編譯源碼和別人編譯好的二進制源碼有多大區別

沒感覺出來它們兩個用上去有什麼不同。
基本上用現成的二進制就行,我見過太多自己編譯的其實就是出於心理作用。

㈧ 求教大神,經常聽說java是解釋性語言,和c這樣的編譯性語言不同,有什麼不同,最後還不都是二進制代碼

沒錯,JAVA是一種解釋性語言。也就是說,編譯處理後的JAVA程序並不是由能被CPU直接識別運行的機器指令構成,而是一種二進制的通用偽代碼。
要運行這種由偽代碼構成的程序,必須要有JAVA虛擬機JVM。
運行時,從程序中取一條偽指令,在JVM中翻譯成一串機器指令,運行。再取一條指令,再翻譯,再運行……
使用JVM的缺點,是它的程序運行效率低,速度慢。
使用JVM的優點,就是不同的計算機硬體和不同的操作系統,只要配上對應的JVM,都可以運行同一個JAVA程序。因而JAVA程序的通用性好,用JAVA開發軟體的人工效率較高。
JAVA一般用來開發那些對通用性要求高而對運行效率要求不很苛刻的應用程序。
C語言和C++等編譯語言的程序,是直接由CPU運行的機器指令,運行時不再需要二次翻譯,所以運行時能最大限度地發揮CPU的效能,運行速度很快。但在不同的硬體或操作系統平台上,程序需要按平台重新編譯,甚至修改或重寫代碼。它的程序缺乏跨平台的通用性,開發軟體的人力投入較大。
對運行速度有很高要求的軟體
,如操作系統,大型游戲的核心引擎,和大多數有較高的運行速度效率要求的應用軟體,多用C++這類編譯性語言開發。

㈨ 同一個文件GCC歷次編譯出來的二進制文件都一樣的嗎

除非你自己寫一個編譯器,要不然是不可能鏈接出不帶elf的二進制文件。只要你在linux下就只能得到elf格式的.

㈩ VB中的順序文件、隨機文件和二進制文件的區別

順序、隨機、二進制是指一個程序打開文件所用的方式
可以順序訪問/隨機訪問,比如標准輸入輸出等特殊文件就只能順序訪問
還可以用文本模式/二進制模式打開,主要是對換行符的處理有所不同

閱讀全文

與編譯順序不同二進制不同相關的資料

熱點內容
pdfdocument 瀏覽:556
gcc編譯vi文件 瀏覽:63
安卓連airpods怎麼找耳機 瀏覽:927
加密貨幣轉賬教程 瀏覽:229
程序員小灰hashmap 瀏覽:838
國語pdf版 瀏覽:184
少兒編程作品美麗的小房子 瀏覽:974
伺服器卡在網頁上怎麼辦 瀏覽:54
用python自製編譯器 瀏覽:951
android分享新浪微博客戶端 瀏覽:26
系統中伺服器在哪裡下載地址 瀏覽:1001
新a4安卓手機怎麼投屏 瀏覽:173
pdftoemf 瀏覽:886
java介面可以實現介面嗎 瀏覽:59
vb編程10個隨機函數 瀏覽:22
程序員個人簡介100 瀏覽:772
土木工程師演算法工程師 瀏覽:92
javaexcel導入oracle 瀏覽:880
如何設置異地伺服器 瀏覽:883
為什麼安卓手機藍牙耳機不會彈窗 瀏覽:547