__fastcall
In __fastcall calling convention, the arguments are passed to the register if possible.
- The first two arguments are passed in register ECX and EDX. The remaining arguments are passed on the stack from Right to Left.
- Callee cleans the stack.
Going back to the assembly code of the main function, the statement
main()::return = fastcallAdd(7, 8, 9, 10);
Ruby
; Line 48 push 10 ; 0000000aH push 9 mov edx, 8 mov ecx, 7 call ?fastcallAdd @@YIHHHHH @Z ; fastcallAdd mov DWORD PTR _result$[ebp], eax |
In fastcallAdd, the arguments are pushed onto the stack in Right to Left order, then the 2 arguments that remain are pushed onto registers EDX and ECX respectively. (Or we can say the first 2 arguments are passed onto ECX and EDX in Left to Right order)
The function with the calling convention __fastcall is fastcallAdd(), which is called on line 48 in the main function. We have seen how the arguments are passed onto the stack. We know that since the caller i.e. main is not doing anything about the stack pointer, it is the callee’s job to clean up the stack.
fastcallAdd()
Ruby
?fastcallAdd @@YIHHHHH @Z PROC ; fastcallAdd, COMDAT ; _a$ = ecx ; _b$ = edx ; File c:\users\ruchit\documents\code\visual studio\visual studio\source.cpp ; Line 20 push ebp mov ebp, esp sub esp, 228 ; 000000e4H push ebx push esi push edi push ecx lea edi, DWORD PTR [ebp- 228 ] mov ecx, 57 ; 00000039H mov eax, - 858993460 ; ccccccccH rep stosd pop ecx mov DWORD PTR _b$[ebp], edx mov DWORD PTR _a$[ebp], ecx mov ecx, OFFSET __F81044A6_source @cpp call @__CheckForDebuggerJustMyCode @4 ; Line 21 mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] add eax, DWORD PTR _c$[ebp] add eax, DWORD PTR _d$[ebp] mov DWORD PTR _e$[ebp], eax ; Line 22 mov eax, DWORD PTR _e$[ebp] ; Line 23 pop edi pop esi pop ebx add esp, 228 ; 000000e4H cmp ebp, esp call __RTC_CheckEsp mov esp, ebp pop ebp ret 8 ?fastcallAdd @@YIHHHHH @Z ENDP ; fastcallAdd |
Explanation
Here, we can see that, the stack pointer is incremented with 8 bytes only. We are only popping two 4-byte integers from the stack. This is because the other 2 arguments are passed into ECX and EDX registers. So, we only need to pop the 2 arguments that are on the stack.
Calling Conventions in C/C++
In C/C++ programming, a calling convention is a set of rules that specify how a function will be called. You might have seen keywords like __cdecl or __stdcall when you get linking errors. For example:
error LNK2019: unresolved external symbol "void __cdecl A(void)" (?A@@YAXXZ) referenced in function _main
Here, we see __cdecl being used. It is one of the calling conventions in C/C++. You can also see code like this in 3rd party libraries.
For example:
extern __m128i __cdecl _mm256_mask_cvtepi32_epi16(__m128i, __mmask8, __m256i);
What are caller and callee?
When we call a function, a stack frame is allocated for that function, arguments are passed to the function, and after the function does its work, the allocated stack frame is deallocated and control is passed to the calling function.
The function that calls the subroutine is called the caller. The function that gets called(i.e. subroutine) by the caller is called the callee.
C++
// C++ Program to illustrate the caller and callee #include <iostream> // callee void func() { std::cout << "Geeks" ; } // caller int main() { // function call func(); return 0; } |
Geeks
In the above code, main() is the caller and func() is the callee.
Contact Us