Click to See Complete Forum and Search --> : calling convention stdcalll and cdecl call


George2
July 17th, 2008, 04:25 AM
Hello everyone,


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.


Dump of file 445.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
000 00000000 DEBUG notype Filename | .file
445.cpp
002 00600C05 ABS notype Static | @comp.id
003 00000001 ABS notype Static | @feat.00
004 00000000 SECT1 notype Static | .drectve
Section length 2A, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT2 notype Static | .debug$S
Section length 5A, #relocs 0, #linenums 0, checksum 0
008 00000000 SECT3 notype Static | .text
Section length 7, #relocs 0, #linenums 0, checksum 96F779C9
00A 00000000 SECT3 notype () External | ?foo@@YAHHDZZ (int __cdecl foo(int,char,...))

String Table Size = 0x12 bytes

Summary

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