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?
thanks in advance,
George
olivthill
July 17th, 2008, 05:22 AM
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.
Igor Vartanov
July 17th, 2008, 06:06 AM
Both stdcall and cdecl calling convention could support variable input parameters? Is that correct?
MSDN, C++ Language Reference
__stdcall
Microsoft Specific
The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl.
The proof:
// 445.cpp
int __stdcall foo(int a, char c, ...) { return 0; }
E:\Temp\445>cl 445.cpp /c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
445.cpp
E:\Temp\445>dumpbin /SYMBOLS 445.obj
Microsoft (R) COFF/PE Dumper Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.
5A .debug$S
2A .drectve
7 .text See the difference. :)
kirants
July 17th, 2008, 01:48 PM
FYI:
Function Calls, Part 2 (Stack and Calling Conventions)
(http://www.codeguru.com/cpp/v-s/tips/debugging/article.php/c14681/)
George2
July 18th, 2008, 12:56 AM
Thanks olivthill,
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?
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.
regards,
George
George2
July 18th, 2008, 12:57 AM
Thanks Igor,
What is the root cause why stdcall does not support variable number of input parameter? Maybe from generated assembly, we could find out?
(I think both caller and callee could get # of input parameters from stack in theory?)
regards,
George
Igor Vartanov
July 18th, 2008, 04:36 AM
Thanks Igor,
What is the root cause why stdcall does not support variable number of input parameter? Maybe from generated assembly, we could find out?Exactly! :)
Let's see, the very basic sample:
// 446cdecl.cpp
int __cdecl foo(int a, char c, ...) { return 0; }
int main() { return foo(0, 0, 0); }
// 445stdcall.cpp
int __stdcall foo(int a, char c) { return 0; }
int main() { return foo(0, 0); }
Compile along with producing ASM:
cl 446cdecl.cpp /c /FA && cl 446stdcall.cpp /c /FA
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
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?)Yep, maybe in theory. But not in practice.
George2
July 21st, 2008, 12:21 AM
Thanks Igor!
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?
regards,
George
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.