CC++ Calling Convention
tkorays(tkorays@hotmail.com)
?
調(diào)用約定(Calling Convention) 是計算機編程中一個比較底層的設(shè)計,它主要涉及:
- 函數(shù)參數(shù)通過寄存器傳遞還是棧?
- 函數(shù)參數(shù)從左到右還是從右到左壓棧?
- 是否支持可變參數(shù)函數(shù)(vararg function or variadic function)。
- 是否需要函數(shù)原型?
- 怎么修飾函數(shù)名,唯一標(biāo)識函數(shù)?
- 調(diào)用者(caller)還是被調(diào)用者(called or callee)清理堆棧?
1. Calling Conventions
在C和C++中有幾種調(diào)用約定:__cdecl, __stdcall, __fastcall, __thiscall, __clrcall, __vectorcall。下面首先介紹幾種調(diào)用約定。
1.1 __cdecl
C Declaration Calling Convention,C聲明調(diào)用約定。它是C和C++默認(rèn)的調(diào)用約定。特點:
- 堆棧由調(diào)用者清除(手動清除)。
- 參數(shù)從右到左壓棧。
- 支持可變參數(shù)(函數(shù)自己并不知道自己有多少個參數(shù),因此需要調(diào)用者來清除)。
- 編譯后函數(shù)名改編為:“_函數(shù)名”。如_funcname。
1.2 __stdcall
Standard Calling Convention,標(biāo)準(zhǔn)調(diào)用約定。又稱為Pascal Convention。特點:
- 被調(diào)用函數(shù)自動將參數(shù)彈出棧。
- 參數(shù)從右到坐壓棧(和__cdecl一樣),如果調(diào)用類的成員函數(shù),最后壓入this指針。
- 需要一個函數(shù)原型,不支持變參函數(shù)。
- 函數(shù)名改編:“_函數(shù)名@參數(shù)字節(jié)大小十進制”。如_funcname@8。
1.3 __fastcall
Fast Calling Convention,快速調(diào)用約定。通過使用寄存器解決效率問題。特點:
- 函數(shù)參數(shù)部分通過寄存器傳遞,函數(shù)中最左的兩個DWORD(寄存器大小是雙字)或者更小的參數(shù),通過寄存器傳遞。剩下的從右到左堆棧傳遞。
- 函數(shù)名改編:“@函數(shù)名@函數(shù)參數(shù)字節(jié)大小十進制”。
- 返回方式同__stdcall。
1.4 __thiscall
主要用于x86系統(tǒng)中C++的類的成員函數(shù)調(diào)用,使用寄存器ecx來傳遞this指針。參數(shù)從右往左壓棧,返回方式同__stdcall,由被調(diào)用者自己清除堆棧。
1.5 __clrcall
__clrcall是C++ .Net里面的。
1.6 __vectorcall
要求盡可能在寄存器中傳遞參數(shù)。函數(shù)名改編為”@@函數(shù)名@參數(shù)字節(jié)數(shù)十進制”。這是微軟自己添加的標(biāo)準(zhǔn)。 總結(jié)
除了__cdecl(以及__clrcall),其他的都是被調(diào)用者清除堆棧。
2. 函數(shù)名修飾
2.1 C++中函數(shù)名修飾
在C語言中不存在重載,因此不需要擔(dān)心同名函數(shù)問題,但是在C++中,使用C中的函數(shù)名修飾方式就存在問題。對于重載的函數(shù),僅僅憑函數(shù)名和參數(shù)內(nèi)存大小無法完全區(qū)分;類的成員函數(shù)表示并沒有說明。所以在C++中,對于函數(shù)名改編需要一套策略。函數(shù)名格式大致如?FuncName@@YGXZ這種形式。
- 修飾名以?開始,后面接函數(shù)名。
- 函數(shù)名后為@@YG、@@YA、@@YI,分別代表stdcall、cdecl、fastcall。
- @@YG等后面接著參數(shù)類型字符,第一個表示返回值類型。
- 字符串以@Z結(jié)束,如果函數(shù)沒有參數(shù),則直接以Z結(jié)束。
參數(shù)符號如下:
- X: void
- D: char
- E: unsigned char
- F: short
- H: int
- I: unsigned int
- J: long
- K: unsigned long
- M: float
- N: double
- _N: bool
- PA: 指針
- PB: const指針
- U: struct
所以int __stdcall fa();可以改編為:?fa@@YGHXZ;char* fb(int,bool);改編為?fb@@YAPADH_N@Z。
所以在C++中函數(shù)名改編和C不同,如果需要遵循C中的改編方式,可以使用extern "C"{}。
2.2 C++成員函數(shù)名修飾
類的成員函數(shù)的調(diào)用方式為thiscall,其函數(shù)名修飾方式和普通函數(shù)有些差別。成員函數(shù)名改編需在函數(shù)名和參數(shù)中間插入類名。且需要指定函數(shù)一些性質(zhì),如
- public為@@QAE,protected為@@IAE,private為@@AAE
- 如果函數(shù)聲明為const,則public為@QBE,protected為@@IBE,private為@@ABE。
- 如果參數(shù)類型是類實例的引用,則使用“AAV1”,const引用則為ABV1。
如:
- ?FuncA@ClassA@@QAEXH@Z表示void ClassA::FuncA(int);。
- ?FuncB@ClassA@@QAEXABV1@Z表示void ClassA::FuncB(const ClassA&);
轉(zhuǎn)載于:https://www.cnblogs.com/tkorays/p/C_Cpp_Calling_Convention.html
總結(jié)
以上是生活随笔為你收集整理的CC++ Calling Convention的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Shodan新手入坑指南
- 下一篇: s3c2440移植MQTT