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