Home
Home  
Products
Products 
Articles
Articles 
ChaOS
chaOS
Preferences
Preferences
Support Forums
Forums 
About Us
About Us

Forum start - Register
 
Name Password Forgot your password?

Forum start > Miscellaneous > Blog > Calling conventions in Windows on x86
Author
Thread
Pankaj
Member
avatar

 

Location: Mystery Land
Registered: 10/4/2005    Warnings: 0
Calling conventions in Windows on x86
It is 2 AM in the night and i don't feel like sleeping so i thought why not i start my blog and here i am with my first blog entry ever.

People who do programming on Windows in C/C++, might wonder sometime, what is the __cdecl or __stdcall in front of a function declaration? These compiler specific prefixes are basically a way to tell the compiler, how to push the function arguments on the stack and how to pop them off the stack. These prefix defines the contract between Caller (the one who calls a function) and Callee (the called function) for argument passing. This contact is known as Calling convention. Usually we should need only one calling convention for argument passing but Windows compilers provide more than one convention because of historical and performance reasons. The three calling conventions available on windows are:

1. __cdecl
2. __stdcall
3. __fastcall

__fastcall and __stdcall are more efficient than __cdecl but they don't support variable argument functions which is required for functions like printf.

To understand these calling conventions in details, lets take a look at the sample program:

Code
1:    int
2:   __cdecl testCDecl(int a, int b, int c, int d) 
3:   { 
4:      return a; 
5:   } 
6:   
7:   int 
8:   __stdcall testStdcall(int a, int b, int c, int d) 
9:   { 
10:     return a; 
11:  } 
12:  
13:  int 
14:  __fastcall testFastcall(int a, int b, int c, int d) 
15:  { 
16:     return a; 
17:  } 
18:  
19:  
20:  int _tmain(int argc, _TCHAR* argv[]) 
21:  { 
22:     testCDecl(1, 2, 3, 4)
23:     testStdcall(1, 2, 3, 4)
24:     testFastcall(1, 2, 3, 4)
25:  
26:     return 0; 
27:  } 



__cdecl is the original C calling convention. In this convention Caller pushes the function arguments on the stack from right to left. Because this convention allows the caller to push variable number of arguments on the stack (for functions like printf), Callee doesn't know how many bytes it needs to take off from the stack. Hence it is the responsibility of caller to pop these arguments off the stack.

__stdcall (standard calling convention) or also known as PASCAL convention is only supports fixed number of parameters in a function call. In this convention parameters are pushed from right to left but Callee removes them off the stack. This calling convention is the standard calling convention for Win32 APIs.

__fastcall is slightly optimized version of __stdcall convention. It passes first two parameters in ecx and edx respectively but rest of the arguments are pushed on the stack from right to left (similar to other conventions).

Below i will show the disassembly of the code shown above to describe how the parameters are pushed and popped off the stack for the above discussed calling conventions.

Code
1:    ///
2:   /// Disassembly of _tmain 
3:   /// 
4:   int _tmain(int argc, _TCHAR* argv[]) 
5:   { 
6:   push        ebp  
7:   mov         ebp,esp 
8:   
9:      testCDecl(1, 2, 3, 4)
10:  push        4    <- Push arguments right to left 
11:  push        3    <- on the stack for __cdecl funciton 
12:  push        2    <- Each argument takes 4 bytes on x86 
13:  push        1    
14:  call        testCDecl (401630h) 
15:  add         esp,10h <- testCDecl is called, now pop off the 
16:                      <- arguments off the stack by adding 16 
17:                      <- or 10h from esp (or stack pointer) 
18:  
19:     testStdcall(1, 2, 3, 4)
20:  push        4    <- Push arguments right to left 
21:  push        3    <- on the stack for __stdcall funciton 
22:  push        2    <- Each argument takes 4 bytes on x86 
23:  push        1    
24:  call        testStdcall (401640h) 
25:                      <- Notice here that after calling testStdcall 
26:                      <- we don't remove the arguments from the 
27:                      <- stack because in __stdcall functions the 
28:                      <- are removed by the Callee and not caller 
29:  
30:     testFastcall(1, 2, 3, 4)
31:  push        4    
32:  push        3    
33:  mov         edx,2     <- Notice here that first and second arguments 
34:  mov         ecx,1     <- are passed in ecx and edx respectively 
35:  call        testFastcall (401650h) 
36:                      <- same as __stdcall, callee pops the arguments 
37:                      <- off the stack 
38:  
39:     return 0; 
40:  xor         eax,eax 
41:  } 
42:  pop         ebp  
43:  ret 
44:  
45:  
46:  /// 
47:  /// Disassembly of testCDecl 
48:  /// 
49:  int 
50:  __cdecl testCDecl(int a, int b, int c, int d) 
51:  { 
52:  push        ebp  
53:  mov         ebp,esp 
54:     return a; 
55:  mov         eax,dword ptr [a] 
56:  } 
57:  pop         ebp  
58:  ret      
59:  
60:  
61:  /// 
62:  /// Disassembly of testStdCall 
63:  /// 
64:  int 
65:  __stdcall testStdcall(int a, int b, int c, int d) 
66:  { 
67:  push        ebp  
68:  mov         ebp,esp 
69:     return a; 
70:  mov         eax,dword ptr [a] 
71:  } 
72:  pop         ebp  
73:  ret         10h <- return to the return address and remove 
74:                  <- 16 bytes (or 4 arguments a, b, c and d) 
75:                  <- from the stack 
76:  
77:  
78:  
79:  /// 
80:  /// Disassembly of testFastcall 
81:  /// 
82:  int 
83:  __fastcall testFastcall(int a, int b, int c, int d) 
84:  { 
85:  push        ebp  
86:  mov         ebp,esp 
87:  sub         esp,
88:  mov         dword ptr [ebp-8],0CCCCCCCCh 
89:  mov         dword ptr [ebp-4],0CCCCCCCCh 
90:  mov         dword ptr [ebp-8],edx 
91:  mov         dword ptr [ebp-4],ecx 
92:     return a; 
93:  mov         eax,dword ptr [a] 
94:  } 
95:  mov         esp,ebp 
96:  pop         ebp  
97:  ret         8   <- return to the return address and remove 
98:                  <- 8 bytes  or 2 arguments c and d from the 
99:                  <- stack (since a and b were passed in 
100:                  <- registers) 



For C++ member functions "this" pointer is treated as the first argument and is passed in the ecx register. Other parameters are passed as per the calling convention rules described above.

For x86-64 based systems, Microsoft has unified the calling convention but that on some other sleepless night.
__________________
Pankaj Garg

*This posting is provided "AS IS" with no warranties and confers no rights*
10/4/2005 03:50 Link - Ip: Logged - Quote:
rana_raja20
Member


 

Location: 
Registered: 4/6/2006      Warnings: 0
dear pankaj,
plz give more views in the blog section
6/6/2006 09:21 Link - Ip: Logged - Quote:
Forum start > Miscellaneous > Blog > Calling conventions in Windows on x86

Quick reply
You need to login before you can post.
© Copyright www.intellectualheaven.com. All rights reserved. Powered by Windows XP