2014-04-26 60 views
0

我不明白爲什麼下面幾行是使用movl來推送數據在堆棧指針下由GCC生成。C函數調用約定:爲什麼movl代替pushl?

movl -4(%ebp), %eax  # -4(%ebp) <- local variable 1 
movl 8(%ebp), %edx  # 8(%ebp) <- first parameter 
movl %edx, 8(%esp)  # ??? WHY NOT: pushl %edx 
movl %eax, 4(%esp)  # ??? WHY NOT: pushl %eax 
movl -8(%ebp), %eax  # ??? WHY NOT: pushl -8(%ebp) 
movl %eax, (%esp) 
call athena 
movl %eax, f 

(full code)

我想這段代碼試圖推動3個參數的函數調用。但爲什麼不使用pushl。這段代碼的用法是什麼?它是如何工作的?

+0

我不知道它爲什麼這樣工作。也許是因爲代碼與通過寄存器傳遞參數的x86-64相似? (例如,它們只會有一個「裝入值」指令)。 另外,你見過這個問題嗎? http://stackoverflow.com/questions/22267767/why-is-gcc-using-mov-instead-of-push-in-function-calls – Marco

+4

PUSH是一種傳統的指令,在現代內核上執行不力。它對ESP寄存器的值有間接的依賴關係。這使得執行亂序很難。 MOV沒有這樣的問題。如英特爾優化手冊中所述,編碼規則25. –

+0

這裏是否缺少某些東西?我希望在'movel's會是'sub%esp,xxx'之前的某個地方,其中'xxx'是要傳遞參數的大小?然後當電話返回時,不久之後,'add%esp,xxx'? – lurker

回答

2

Hans Passant正確回答。 push/pop操作碼可以分解爲兩個微操作,它們執行內存移動和堆棧指針的遞增/遞減。如果堆棧指針或任何指針被更新,然後立即用於下一個操作碼,則通常會發生執行停頓。通過堆棧指針訪問各個內存位置 - 就像在你的例子中那樣 - 不會有停頓,操作可以配對,允許它們同時執行。

任何超標量CPU類型將嘗試在單個循環中執行多個操作碼,如果它們的結果/源相互無關。編譯器正在爲你做些事情來加速執行,手工操作相當麻煩。這些操作碼可能會佔用更多的空間,但它們的執行速度大約快兩倍 - 所有其他的事情都是相同的。