2013-02-03 21 views
1

在C++中調用函數時,推送rdi和pop rdi的目的是什麼? VS2010,64位,調試,沒有優化彙編程序在函數調用時推送rdi,pop rdi

C++

int calc() 
{ 
    return 8 + 7; 
} 

拆卸:

int calc() 
{ 
000000013F0B1020 push  rdi 
    return 8 + 7; 
000000013F0B1022 mov   eax,0Fh 
} 
000000013F0B1027 pop   rdi 
000000013F0B1028 ret 
+1

難道是某種形式的「後衛」的事?我認爲我讀過的地方是MSVC *總是在每個函數的頂部留下一些空間...... –

+0

@KerrekSB,如果它是在函數代碼的開始處留下一些「空間」的問題,那麼NOOPs會是一個很大的比無用的推動和彈出更明智的選擇。 –

回答

4

沒有目的吧。這是未經優化的代碼的常見工件。代碼生成器發出push edi指令以預期必須執行添加。 EDI寄存器必須在函數調用中保留。但後來,他發現可以在編譯時加入。

擺脫這樣的無關代碼需要"peephole optimization"。但是,在Debug版本中沒有啓用該優化。要知道真正的代碼是什麼樣的,你必須打開優化器,最好通過構建Release版本來完成。這實際上將完全消除的功能,你就可以阻止它有這樣做:

__declspec(noline) int calc() 
{ 
    return 8 + 7; 
} 

其中在發佈版本產生:

return 8 + 7; 
000007F7038E1000 mov   eax,0Fh 
000007F7038E1005 ret 
2

你有沒有聽說過 「調用者保存」 和 「被叫保存」 登記?

由於您的CPU只有少量的有限數量的寄存器,因此調用者/被調用函數通常不可能總是使用不同的寄存器。如果呼叫者功能和呼叫功能都要使用同一個寄存器,這意味着呼叫者的值必須在呼叫之前/之後保存/恢復。

保存/恢復寄存器的值可以由調用者或被調用者來完成 - 哪一個是傳統約定。 「調用者保存」寄存器的好處是,如果調用者知道在調用之後不需要寄存器XYZ中的值,則可以省略保存/恢復操作。 「被調用者保存」寄存器的好處是,如果被調用者知道它不會修改寄存器XYZ中的值,它可以省略保存/恢復操作。

我猜你的編譯器將RDI視爲被調用者保存寄存器,但不會省略不必要的保存/恢復操作,除非您打開了編譯器優化。 (如果有人知道這是不正確,請發佈另一個答案!)

更新:我發現在x86調用約定的文章:http://en.wikipedia.org/wiki/X86_calling_conventions

這似乎證實,與大多數調用約定,RDI將被叫-保存。這並不能解釋爲什麼它不會推送和彈出所有其他被叫保存寄存器。也許這裏還有別的事情要做。