Microsoft函數調用約定

原帖:http://www.cpper.com/site/comments/ms_calling_conventions/

對於所有調用共有的約定:ebx、ebp、esi、edi都是calle-save,即由被調用的函數負責它們的保存(如果被調用函數用到了這些寄存器的話)

先看函數調用發生了什麼:(win32下)
1、所有參數提升到4bytes的倍數
2、執行call指令
3、將ebx、ebp、esi、edi保存在棧上,這一步稱爲function prolog
4、將返回值放在eax中(返回int64放在edx:eax中,返回double放在浮點寄存器中。複雜的數據結構在caller的棧中分配空間,將首地址做爲最後壓棧的參數(我拿__cdecl試的),callee返回的時候將返回值放在這個指針指向的地址)
5、取出ebx、ebp、esi、edi,這一步稱爲function epilog
6、清空棧,保持堆棧平衡,這一步稱爲stack cleanup

具體的調用約定:
1、__cdecl
壓棧順序:從右至左
清棧:函數調用者負責清空,稱爲caller cleanup
名字修飾(name decoration):在函數名前加上下劃線做前綴,比如_foo
注:c/c++函數的缺省調用約定

2、__stdcall
壓棧順序:從右至左
清棧:被調用函數負責清空,稱爲callee cleanup
名字修飾:在函數名前加上下劃線做前綴,名字後用@加上函數參數大小做後綴,如_foo@8
注:WINAPI就是__stdcall的#define

3、__fastcall
壓棧順序:第一個參數放在ecx,第二個參數放在edx,其餘從右至左
清棧:callee cleanup
名字修飾:在函數名前加上@做前綴,名字後用@加上函數參數大小做後綴,如@foo@8
注:名字叫fast實際就不一定了……

4、thiscall
壓棧順序:this指針(cpp非靜態成員函數特有)放在ecx,其餘從右至左
清棧:callee cleanup
注:cpp非靜態成員函數默認的調用約定

5、naked
壓棧順序:從右至左
清棧:caller cleanup
注:VxDs用的調用約定,將__declspec(naked)寫在函數定義處(注意,不是聲明)

這篇文章把naked作爲calling convention: http://www.cs.cornell.edu/courses/cs412/2001sp/resources/microsoft-calling-conventions.htm 

但naked應該算不上調用約定了,只是單純地將c/c++代碼翻譯成asm,連esp、ebp之間的保存、mov都沒有就直接拿ebp來尋址了,函數結束後也不管ret,太naked了!

補充:c允許可變參數(例如printf),爲了方便地使用這些函數,所以__cdecl要
1、從右至左壓棧(這樣才能知道第一個參數在堆棧中的地址)
2、caller cleanup(因爲只有caller才知道這次調用push了多少參數


函數調用約定的歷史——16位的世界:

對所有的調用約定:
1、用dx:ax或ax保存返回值
2、由於cx不能尋址,所以還需要一個bx來scratch(就是不需要callee-save的寄存器)

具體的調用約定
1、__cdecl
名字修飾在函數前加下劃線可能是爲了區別函數名和彙編語言的關鍵字

2、__pascal
自左至右傳參、callee cleanup
比較有意思的是名字修飾把函數名轉換爲大寫,嗯,pascal大小寫無關……
幾乎所有的win16函數都是用pascal調用約定,因爲callee-clean的操作比caller-clean要節省3bytes的空間

3、__fortran
和pascal一樣

4、__fastcall
和win32下一樣,把ecx、edx換爲cx、dx罷了
這個fast可是未必,如果函數中的計算要用到cx、dx就免不了把cx、dx壓棧的操作了,所以這種調用約定僅僅可能對短小的leaf function(就是不調用其他函數的函數)快一些,甚至對這類函數都快不了……


參考:
1. Calling Conventions Demystified, by Nemanja Trifunovic
http://www.codeproject.com/cpp/calli...emystified.asp
2. The history of calling conventions, part 1
https://blogs.msdn.com/oldnewthing/a.../02/47184.aspx
3. The history of calling conventions, part 2
https://blogs.msdn.com/oldnewthing/a.../07/48303.aspx
4. The history of calling conventions, part 3
https://blogs.msdn.com/oldnewthing/a.../08/48616.aspx
5. The history of calling conventions, part 4: ia64
https://blogs.msdn.com/oldnewthing/a.../13/58199.aspx

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章