Both stdcall and cdecl calling convention could support variable input parameters? Is that correct?
(I think stdcall is using RET N and cdecl is using ESP - N, so both are capable to handle variable number of input parameter, like printf?)
BTW: I have this question because I have something in mind that only one of them supports variable number of parameters, but after reading assembly language code, I think both of them are able to support this feature?
Yes, both stdcall and cdecl calling conventions support variable input parameters. The difference is that the stack pointer is reset by the callee with stdcall, and the stack pointer is reset by the caller with cdecl.
The isssue of variable arguments depends on the argument passing order and the syntax of your functions.
With the C (stdcall or cdecl) order, arguments are passed from right to left, whereas with the Pascal order, arguments are passed from left to right.
Let's look at printf("x=%d", y=%d", x, y);
Let's say the stack pointer is 100 before the call.
Three arguments are pushed onto the stack.
With the C order (stdcall and cdecl), we have:
push y ; stack pointer is 96
push x ; stack pointer is 92
push address of "x=%d", y=%d" ; stack pointer is 88.
Inside printf, the program will examine the argument which is the closest to the stack pointer, ie. address of "x=%d", y=%d", and will find that there are two percent signs, therefore two more arguments on the stack.
With the Pascal order
push address of "x=%d", y=%d" ; stack pointer is 96.
push x ; stack pointer is 92
push y ; stack pointer is 88
Inside printf, the program will examine the argument which is the closest to the stack pointer, ie. y. Now, the program does not know if there are other arguments. However, with this convention, variable arguments are possible if printf() syntax were changed in order to have the format string at the end instead of at the beginning.
I do not fully agree with you that both stdcall and cdecl call support variable input parameters. Please refer to Igor's comment below and find only cdecl supports variable input parameter feature. Any comments?
Originally Posted by olivthill
Yes, both stdcall and cdecl calling conventions support variable input parameters. The difference is that the stack pointer is reset by the callee with stdcall, and the stack pointer is reset by the caller with cdecl.
The isssue of variable arguments depends on the argument passing order and the syntax of your functions.
With the C (stdcall or cdecl) order, arguments are passed from right to left, whereas with the Pascal order, arguments are passed from left to right.
Let's look at printf("x=%d", y=%d", x, y);
Let's say the stack pointer is 100 before the call.
Three arguments are pushed onto the stack.
With the C order (stdcall and cdecl), we have:
push y ; stack pointer is 96
push x ; stack pointer is 92
push address of "x=%d", y=%d" ; stack pointer is 88.
Inside printf, the program will examine the argument which is the closest to the stack pointer, ie. address of "x=%d", y=%d", and will find that there are two percent signs, therefore two more arguments on the stack.
With the Pascal order
push address of "x=%d", y=%d" ; stack pointer is 96.
push x ; stack pointer is 92
push y ; stack pointer is 88
Inside printf, the program will examine the argument which is the closest to the stack pointer, ie. y. Now, the program does not know if there are other arguments. However, with this convention, variable arguments are possible if printf() syntax were changed in order to have the format string at the end instead of at the beginning.
PUBLIC ?foo@@YAHHDZZ ; foo
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_c$ = 12 ; size = 1
?foo@@YAHHDZZ PROC NEAR ; foo
; File e:\temp\446\446cdecl.cpp
; Line 1
push ebp
mov ebp, esp
xor eax, eax
pop ebp
ret 0
?foo@@YAHHDZZ ENDP ; foo
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odt
_TEXT SEGMENT
_main PROC NEAR
; Line 2
push ebp
mov ebp, esp
push 0
push 0
push 0
call ?foo@@YAHHDZZ ; foo
add esp, 12 ; 0000000cH
compiler knows exactly the size of the stack on the caller side
pop ebp
ret 0
_main ENDP
Code:
PUBLIC ?foo@@YGHHD@Z ; foo
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_c$ = 12 ; size = 1
?foo@@YGHHD@Z PROC NEAR ; foo
; File e:\temp\446\446stdcall.cpp
; Line 1
push ebp
mov ebp, esp
xor eax, eax
pop ebp
ret 8 ; the function body knows the
; exact size of stack to be cleared
; (defined by function prototype)
; but knows nothing about the actual stack size used
?foo@@YGHHD@Z ENDP ; foo
_TEXT ENDS
PUBLIC _main
; Function compile flags: /Odt
_TEXT SEGMENT
_main PROC NEAR
; Line 2
push ebp
mov ebp, esp
push 0
push 0
call ?foo@@YGHHD@Z ; foo
pop ebp
ret 0
_main ENDP
(I think both caller and callee could get # of input parameters from stack in theory?)
I think the reason why stdcall can not have variable number of input parameter is, we can not have a common code which is capable to pop variable number of input parameters (a specific function is common code base, and needs common code to pop a specific number (not variable) of elements from stack, but if input parameter number is variable, it is impossible to have such a common code base), correct?
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.