2016-04-24 39 views
5

我目前正在學習彙編和C編程語言,我有幾個關於它的問題。組裝與C代碼比較

C代碼

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; 
} 

彙編代碼

movl 16(%ebp),%eax   z 
leal (%eax,%eax,2), %eax z*3 
sall $4,%eax    t2 = z*48 
movl 12(%ebp),%edx   y 
addl 8(%ebp),%edx   t1 = x+y 
andl $65535,%edx   t3 = t1&0xFFFF 
imull %edx,%eax    Return t4 = t2*t3 

而不是使用萊亞爾,然後由4移動由48乘Z,可我只是用imull $ 48,%EAX的?

此外,這是多次使用%edx寄存器。這是否意味着t1被覆蓋?換句話說,如果我願意,我還能在t4之前檢索t1嗎?

+1

是,否(變量't1'被優化掉),並且編號。對於最後一個問題'x + y'是計算出來的,但是從未保存過。 _EDX_在'addl 8(%ebp),%edx'後面具有值'x + y',但是指令'andl $ 65535,%edx'破壞了它。如果您在'addl 8(%ebp),%edx'之後將_EDX_移動到像_ECX_這樣的寄存器,那麼您仍然可以訪問計算的x + y部分。 –

+0

很酷。 C代碼是否真的會在幕後翻譯,以至於它不會將每個變量存儲到它自己的寄存器中? – Dylan

+2

如果不需要它,則不需要。這是優化編譯器的功能。 – usr2564301

回答

2

嘗試將程序集與您的代碼逐行匹配可能不是解決此問題的最佳方法。編譯器進行了幾次優化,以使程序儘可能高效地運行,這就是爲什麼您可能會注意到代碼之間存在一些不一致的原因。

爲了回答你的第一個問題,從技術上講,這可以起作用,但編譯器再一次做了幾次優化。所以雖然使用imul看起來更直觀,但編譯器確定leal和sall更有效率。 編輯:我只想指出,在可能的情況下,移位操作符幾乎總是用來代替imul。對於CPU而言,位移要便宜得多,因爲它實際上只是移位位值,而不是嘗試執行一些可能需要更多CPU時間的數學運算。

現在關於「覆蓋」t1。程序集沒有任何有關程序變量的信息 - 它只知道它需要對某些值執行一些操作。雖然程序集有可能使用4個不同的寄存器來存儲t1-4,但編譯器確定這是不必要的,並且對於所有的值只需要2個寄存器。如果你仔細想想,這應該是有道理的。你的功能可以簡化爲幾行代碼。很明顯,這不是一個好主意,因爲這會讓人無法閱讀,但是彙編不一定被設計爲「可讀」。如果您在返回t4之前回到程序並執行了其他一些t1操作,則可能會注意到您的程序集與以前不同,並且可能正在使用另一個寄存器,具體取決於值的使用方式。

如果您真的想在彙編中使用您的程序的準系統版本,請使用-Og標誌編譯來關閉編譯器優化。它可能仍然不完全符合您的代碼,但它可能會使您更容易理解正在發生的事情。

+1

謝謝。你所說的一切都對我有意義。這很酷,它如何在這樣的幕後進行優化。 – Dylan

+1

在這個[Agner Fog文檔](http://www.agner。組織/優化/ instruction_tables.pdf)。根據LEAL的架構,甚至可能無法到達ALU。在一些x86架構上,它是作爲AGU的一部分完成的。 –