I know what the differences between __cdecl
and __stdcall
are, but I'm not quite sure as to why __stdcall
is ignored by the compiler in x64 builds.
The functions in the following code
int __stdcall stdcallFunc(int a, int b, int c, int d, int e, int f, int g)
{
return a + b + c + d + e + f + g;
}
int __cdecl cdeclFunc(int a, int b, int c, int d, int e, int f, int g)
{
return a + b + c + d + e + f + g;
}
int main()
{
stdcallFunc(1, 2, 3, 4, 5, 6, 7);
cdeclFunc(1, 2, 3, 4, 5, 6, 7);
return 0;
}
have enough parameters to exceed the available CPU registers. Therefore, some arguments must be passed via the stack. I'm not fluent in assembly but I noticed some differences between x86 and x64 assembly.
x64
main PROC
$LN3:
sub rsp, 72 ; 00000048H
mov DWORD PTR [rsp+48], 7
mov DWORD PTR [rsp+40], 6
mov DWORD PTR [rsp+32], 5
mov r9d, 4
mov r8d, 3
mov edx, 2
mov ecx, 1
call ?stdcallFunc@@YAHHHHHHHH@Z ; stdcallFunc
mov DWORD PTR [rsp+48], 7
mov DWORD PTR [rsp+40], 6
mov DWORD PTR [rsp+32], 5
mov r9d, 4
mov r8d, 3
mov edx, 2
mov ecx, 1
call ?cdeclFunc@@YAHHHHHHHH@Z ; cdeclFunc
xor eax, eax
add rsp, 72 ; 00000048H
ret 0
main ENDP
x86
_main PROC
push ebp
mov ebp, esp
push 7
push 6
push 5
push 4
push 3
push 2
push 1
call ?stdcallFunc@@YGHHHHHHHH@Z ; stdcallFunc
push 7
push 6
push 5
push 4
push 3
push 2
push 1
call ?cdeclFunc@@YAHHHHHHHH@Z ; cdeclFunc
add esp, 28 ; 0000001cH
xor eax, eax
pop ebp
ret 0
_main ENDP
- The first 4 arguments are, as expected, passed via registers in x64.
- The remaining arguments are put on the stack in the same order as in x86.
- Contrary to x86, in x64 we don't use
push
instructions. Instead we reserve enough stack space at the beginning ofmain
and usemov
instructions to add the arguments to the stack. - In x64, no stack cleanup is happening after both
call
s, but at the end ofmain
.
This brings me to my questions:
- Why does x64 use
mov
rather thanpush
? I assume it's just more efficient and wasn't available in x86. - Why is there no stack cleanup after the
call
instructions in x64? - What's the reason that Microsoft chose to ignore
__stdcall
in x64 assembly? From the docs:On ARM and x64 processors, __stdcall is accepted and ignored by the compiler
Here is the example code and assembly.