問題描述
在 C/C++ 中有不同的調用約定:stdcall
、extern
、pascal
等.有多少這樣的調用約定可用,每個是什么意思?有沒有描述這些的鏈接?
There are different calling conventions available in C/C++: stdcall
, extern
, pascal
, etc. How many such calling conventions are available, and what do each mean? Are there any links that describe these?
推薦答案
簡單回答:我使用 cdecl、stdcall 和 fastcall.我很少使用fastcall.stdcall 用于調用 Windows API 函數(shù).
詳細答案(從 維基百科竊取):
Detailed answer (Stolen from Wikipedia):
cdecl - 在 cdecl 中,子程序參數(shù)在堆棧上傳遞.整數(shù)值和內(nèi)存地址在 EAX 寄存器中返回,浮點值在 ST0 x87 寄存器中返回.寄存器 EAX、ECX 和 EDX 是調用者保存的,其余的都是被調用者保存的.調用新函數(shù)時,x87 浮點寄存器 ST0 到 ST7 必須為空(彈出或釋放),退出函數(shù)時 ST1 到 ST7 必須為空.不用于返回值時,ST0 也必須為空.
cdecl - In cdecl, subroutine arguments are passed on the stack. Integer values and memory addresses are returned in the EAX register, floating point values in the ST0 x87 register. Registers EAX, ECX, and EDX are caller-saved, and the rest are callee-saved. The x87 floating point registers ST0 to ST7 must be empty (popped or freed) when calling a new function, and ST1 to ST7 must be empty on exiting a function. ST0 must also be empty when not used for returning a value.
系統(tǒng)調用 - 這與 cdecl 類似,參數(shù)從右向左推送.EAX、ECX 和 EDX 不會被保留.雙字中參數(shù)列表的大小在AL中傳遞.
syscall - This is similar to cdecl in that arguments are pushed right-to-left. EAX, ECX, and EDX are not preserved. The size of the parameter list in doublewords is passed in AL.
pascal - 參數(shù)按從左到右的順序入棧(與 cdecl 相反),被調用者負責在返回前平衡棧.
pascal - the parameters are pushed on the stack in left-to-right order (opposite of cdecl), and the callee is responsible for balancing the stack before return.
stdcall - stdcall[4] 調用約定是 Pascal 調用約定的變體,其中被調用者負責清理堆棧,但參數(shù)被推入右側的堆棧中-從左到右的順序,就像在 _cdecl 調用約定中一樣.寄存器 EAX、ECX 和 EDX 被指定在函數(shù)內(nèi)使用.返回值存儲在 EAX 寄存器中.
stdcall - The stdcall[4] calling convention is a variation on the Pascal calling convention in which the callee is responsible for cleaning up the stack, but the parameters are pushed onto the stack in right-to-left order, as in the _cdecl calling convention. Registers EAX, ECX, and EDX are designated for use within the function. Return values are stored in the EAX register.
fastcall - __fastcall 約定(又名 __msfastcall)傳遞適合 ECX 和 EDX 的前兩個參數(shù)(從左到右計算).剩余的參數(shù)從右到左壓入堆棧.
fastcall - __fastcall convention (aka __msfastcall) passes the first two arguments (evaluated left to right) that fit into ECX and EDX. Remaining arguments are pushed onto the stack from right to left.
vectorcall - 在 Visual Studio 2013 中,Microsoft 引入了 __vectorcall 調用約定,以應對游戲、圖形、視頻/音頻和編解碼器開發(fā)人員的效率問題.[7]對于 IA-32 和 x64 代碼,__vectorcall 分別類似于 __fastcall 和原始 x64 調用約定,但對其進行了擴展以支持使用 SIMD 寄存器傳遞向量參數(shù).對于 x64,當前六個參數(shù)中的任何一個是向量類型(float、double、__m128、__m256 等)時,它們通過相應的 XMM/YMM 寄存器傳入.類似地,對于 IA-32,最多六個 XMM/YMM 寄存器從左到右依次分配給向量類型參數(shù),而不管位置如何.此外,__vectorcall 增加了對傳遞同構向量聚合 (HVA) 值的支持,這些值是復合類型,僅由最多四個相同的向量類型組成,使用相同的六個寄存器.一旦為向量類型參數(shù)分配了寄存器,無論位置如何,未使用的寄存器都會從左到右分配給 HVA 參數(shù).使用前四個 XMM/YMM 寄存器返回結果向量類型和 HVA 值.
vectorcall - In Visual Studio 2013, Microsoft introduced the __vectorcall calling convention in response to efficiency concerns from game, graphic, video/audio, and codec developers.[7] For IA-32 and x64 code, __vectorcall is similar to __fastcall and the original x64 calling conventions respectively, but extends them to support passing vector arguments using SIMD registers. For x64, when any of the first six arguments are vector types (float, double, __m128, __m256, etc.), they are passed in via the corresponding XMM/YMM registers. Similarly for IA-32, up to six XMM/YMM registers are allocated sequentially for vector type arguments from left to right regardless of position. Additionally, __vectorcall adds support for passing homogeneous vector aggregate (HVA) values, which are composite types consisting solely of up to four identical vector types, using the same six registers. Once the registers have been allocated for vector type arguments, the unused registers are allocated to HVA arguments from left to right regardless of position. Resulting vector type and HVA values are returned using the first four XMM/YMM registers.
safecall - Microsoft Windows 上的 n Delphi 和 Free Pascal,safecall 調用約定封裝了 COM(組件對象模型)錯誤處理,因此異常不會泄露給調用者,而是在COM/OLE 要求的 HRESULT 返回值.從 Delphi 代碼調用安全調用函數(shù)時,Delphi 還會自動檢查返回的 HRESULT 并在必要時引發(fā)異常.
safecall - n Delphi and Free Pascal on Microsoft Windows, the safecall calling convention encapsulates COM (Component Object Model) error handling, thus exceptions aren't leaked out to the caller, but are reported in the HRESULT return value, as required by COM/OLE. When calling a safecall function from Delphi code, Delphi also automatically checks the returned HRESULT and raises an exception if necessary.
safecall 調用約定與 stdcall 調用約定相同,除了異常在 EAX 中作為 HResult(而不是在 FS:[0] 中)傳遞回調用者,而函數(shù)結果通過引用傳遞給堆棧就好像它是最終的輸出"參數(shù)一樣.當從 Delphi 調用一個 Delphi 函數(shù)時,這個調用約定將像任何其他調用約定一樣出現(xiàn),因為盡管異常在 EAX 中被傳回,但它們會被調用者自動轉換回正確的異常.使用其他語言創(chuàng)建的 COM 對象時,HResults 將作為異常自動引發(fā),并且 Get 函數(shù)的結果在結果中而不是參數(shù)中.在 Delphi 中使用 safecall 創(chuàng)建 COM 對象時,無需擔心 HResults,因為異常可以正常引發(fā),但在其他語言中將被視為 HResults.
The safecall calling convention is the same as the stdcall calling convention, except that exceptions are passed back to the caller in EAX as a HResult (instead of in FS:[0]), while the function result is passed by reference on the stack as though it were a final "out" parameter. When calling a Delphi function from Delphi this calling convention will appear just like any other calling convention, because although exceptions are passed back in EAX, they are automatically converted back to proper exceptions by the caller. When using COM objects created in other languages, the HResults will be automatically raised as exceptions, and the result for Get functions is in the result rather than a parameter. When creating COM objects in Delphi with safecall, there is no need to worry about HResults, as exceptions can be raised as normal but will be seen as HResults in other languages.
Microsoft X64 調用約定 - Windows 上遵循 Microsoft x64 調用約定[12][13],并且預啟動 UEFI(用于 x86-64 上的長模式).它使用寄存器 RCX、RDX、R8、R9 作為前四個整數(shù)或指針參數(shù)(按此順序),而 XMM0、XMM1、XMM2、XMM3 用于浮點參數(shù).額外的參數(shù)被壓入堆棧(從右到左).如果 64 位或更少,則在 RAX 中返回整數(shù)返回值(類似于 x86).浮點返回值在 XMM0 中返回.長度小于 64 位的參數(shù)不進行零擴展;高位不歸零.
Microsoft X64 Calling Convention - The Microsoft x64 calling convention[12][13] is followed on Windows and pre-boot UEFI (for long mode on x86-64). It uses registers RCX, RDX, R8, R9 for the first four integer or pointer arguments (in that order), and XMM0, XMM1, XMM2, XMM3 are used for floating point arguments. Additional arguments are pushed onto the stack (right to left). Integer return values (similar to x86) are returned in RAX if 64 bits or less. Floating point return values are returned in XMM0. Parameters less than 64 bits long are not zero extended; the high bits are not zeroed.
在 Windows 上下文中(無論是使用 Microsoft 還是非 Microsoft 工具)針對 x64 架構進行編譯時,只有一種調用約定——此處描述的約定,因此 stdcall、thiscall、cdecl、fastcall 等都是現(xiàn)在都一樣了.
When compiling for the x64 architecture in a Windows context (whether using Microsoft or non-Microsoft tools), there is only one calling convention – the one described here, so that stdcall, thiscall, cdecl, fastcall, etc., are now all one and the same.
在 Microsoft x64 調用約定中,調用者有責任在調用函數(shù)之前在堆棧上分配 32 字節(jié)的影子空間"(無論實際使用的參數(shù)數(shù)量如何),并在調用之后彈出堆棧稱呼.陰影空間用于溢出 RCX、RDX、R8 和 R9,[14] 但必須可供所有函數(shù)使用,即使是那些參數(shù)少于四個的函數(shù).
In the Microsoft x64 calling convention, it is the caller's responsibility to allocate 32 bytes of "shadow space" on the stack right before calling the function (regardless of the actual number of parameters used), and to pop the stack after the call. The shadow space is used to spill RCX, RDX, R8, and R9,[14] but must be made available to all functions, even those with fewer than four parameters.
寄存器 RAX、RCX、RDX、R8、R9、R10、R11 被認為是易失性的(調用者保存的).[15]
The registers RAX, RCX, RDX, R8, R9, R10, R11 are considered volatile (caller-saved).[15]
寄存器 RBX、RBP、RDI、RSI、RSP、R12、R13、R14 和 R15 被認為是非易失性的(被調用者保存的).[15]
The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are considered nonvolatile (callee-saved).[15]
例如,一個接受 5 個整數(shù)參數(shù)的函數(shù)將在寄存器中取第一個到第四個,第五個將被推到陰影空間的頂部.所以當被調用的函數(shù)進入時,堆棧將由(升序)返回地址,后跟影子空間(32字節(jié)),后跟第五個參數(shù)組成.
For example, a function taking 5 integer arguments will take the first to fourth in registers, and the fifth will be pushed on the top of the shadow space. So when the called function is entered, the stack will be composed of (in ascending order) the return address, followed by the shadow space (32 bytes) followed by the fifth parameter.
在 x86-64 中,Visual Studio 2008 在 XMM6 和 XMM7(以及 XMM8 到 XMM15)中存儲浮點數(shù);因此,對于 x86-64,用戶編寫的匯編語言例程必須保留 XMM6 和 XMM7(與 x86 相比,其中用戶編寫的匯編語言例程不需要保留 XMM6 和 XMM7).換句話說,當從 x86 移植到 x86-64 時,必須更新用戶編寫的匯編語言例程,以在函數(shù)之前/之后保存/恢復 XMM6 和 XMM7.
In x86-64, Visual Studio 2008 stores floating point numbers in XMM6 and XMM7 (as well as XMM8 through XMM15); consequently, for x86-64, user-written assembly language routines must preserve XMM6 and XMM7 (as compared to x86 wherein user-written assembly language routines did not need to preserve XMM6 and XMM7). In other words, user-written assembly language routines must be updated to save/restore XMM6 and XMM7 before/after the function when being ported from x86 to x86-64.
這篇關于C/C++ 中有哪些不同的調用約定,每個約定是什么意思?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!