Welcome to MSDN Blogs Sign in | Join | Help

The history of calling conventions, part 3

Okay, here we go: The 32-bit x86 calling conventions.

(By the way, in case people didn't get it: I'm only talking in the context of calling conventions you're likely to encounter when doing Windows programming or which are used by Microsoft compilers. I do not intend to cover calling conventions for other operating systems or that are specific to a particular language or compiler vendor.)

Remember: If a calling convention is used for a C++ member function, then there is a hidden "this" parameter that is the implicit first parameter to the function.

All

The 32-bit x86 calling conventions all preserve the EDI, ESI, EBP, and EBX registers, using the EDX:EAX pair for return values.

C (__cdecl)

The same constraints apply to the 32-bit world as in the 16-bit world. The parameters are pushed from right to left (so that the first parameter is nearest to top-of-stack), and the caller cleans the parameters. Function names are decorated by a leading underscore.

__stdcall

This is the calling convention used for Win32, with exceptions for variadic functions (which necessarily use __cdecl) and a very few functions that use __fastcall. Parameters are pushed from right to left [corrected 10:18am] and the callee cleans the stack. Function names are decorated by a leading underscore and a trailing @-sign followed by the number of bytes of parameters taken by the function.

__fastcall

The first two parameters are passed in ECX and EDX, with the remainder passed on the stack as in __stdcall. Again, the callee cleans the stack. Function names are decorated by a leading @-sign and a trailing @-sign followed by the number of bytes of parameters taken by the function (including the register parameters).

thiscall

The first parameter (which is the "this" parameter) is passed in ECX, with the remainder passed on the stack as in __stdcall. Once again, the callee cleans the stack. Function names are decorated by the C++ compiler in an extraordinarily complicated mechanism that encodes the types of each of the parameters, among other things. This is necessary because C++ permits function overloading, so a complex decoration scheme must be used so that the various overloads have different decorated names.

There are some nice diagrams on MSDN illustrating some of these calling conventions.

Remember that a calling convention is a contract between the caller and the callee. For those of you crazy enough to write in assembly language, this means that your callback functions need to preserve the registers mandated by the calling convention because the caller (the operating system) is relying on it. If you corrupt, say, the EBX register across a call, don't be surprised when things fall apart on you. More on this in a future entry.

Published Thursday, January 08, 2004 7:00 AM by oldnewthing
Filed under:

Comments

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 7:20 AM by Ian Hanschen
Raymond,
Great series. Do you know the what & when as far as the 0xDCBAABCD cardinal passed in when calling wndprocs?
-Ian

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 7:30 AM by Raymond Chen
"More on this in a future entry."

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 7:38 AM by Ian Hanschen
Sorry :)
-Ian

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 8:09 AM by Frederik Slijkerman
Honorable mention for Borland's __fastcall convention, borrowed from Delphi, which passes the first three parameters in EAX, EDX, ECX and can be slightly more efficient.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 9:59 AM by Florian
Hmmm, you said that for __cdecl the parameters are pushed from right to left and for __stdcall they are pushed from left to right. But in the diagram on MSDN the stack looks identical for both calling conventions. I assume you are right and they are wrong?

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 10:21 AM by Raymond Chen
D'oh, you're right. __stdcall goes right to left, just like __cdecl. I'll fix the body text.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 12:42 PM by Gene Hamilton
I was stepping through some code with the debugger to take a look for myself these calling conventions in action. (using VS.NET 2002 btw) And I noticed something odd. The 'call' instruction jumpes to an address which contains a single jmp instruction, which in turn 'jmp's to the real function. This is only in the 'Debug' version, not 'Release'

I also noticed after the call instruction the address it moves to, there are other jmp instructions in surrounding memory to other functions.

Here is an example.

...
call myfunc
...

myfunc:
jmp realmyfunc

realmyfunc:
...
...
ret

My Question: What is the purpose of this jmp instruction between call and the actual function? I might be answering my own question here, but here it goes.

I know if you include __declspec(dllimport) to an imported function from a dll, the code looks something like this:

CALL DWORD PTR [0x00405030]

otherwise if you don't it generates this:

CALL 0x0040100C
•••
0x0040100C:
JMP DWORD PTR [0x00405030]

Similar to was I was seeing. I know this happens because the compiler does not know if the function is static or in a dll. So it generates code like this CALL XXXXXXXX and leaves the linker to fill in the rest.

Or is it done for another reason?

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 12:52 PM by Raymond Chen
You probably turned on incremental linking.

http://msdn.microsoft.com/library/en-us/vccore98/HTML/_core_.2f.incremental.asp

On of the consequences of incremental linking called out in the documentation is "May contain jump thunks to handle relocation of functions to new addresses."

If you understand what incremental linking is trying to do, the need for this becomes more obvious.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 1:25 PM by Terry Denham
This may be off topic but does the virtual function table behave similarly to these jump to address and then jump to final address like the incremental linking comment above.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 2:13 PM by Mr. X
Calling conventions are stupid. Any good compilers (such as GCC) won't have them, except for the mandatory 'extern "C"' construct so that C++ programs can call C functions correctly.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 2:16 PM by Raymond Chen
Clearly you need a calling convention or the caller and callee could never communicate with each other. Perhaps you mean "multiple calling conventions are stupid". The hard part then is choosing the "one true" calling convention that works great for everybody.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 2:54 PM by Mike Dimmick
IIRC, the virtual function table is normally implemented simply as a table of addresses. The compiled code dereferences the vptr, which is the first member of the object, to locate the vtbl, then makes an indirect call through that.

On some processors (e.g. the Itanium) the table also includes a global pointer value (2MB of module-relative data can be accessed via this pointer).

I was about to ask why x86 has three calling conventions on 32-bit desktop Windows, but I assume it's for much the same reasons as 16-bit code did (which you mentioned in part 1).

IIRC, Windows CE on x86 only ever uses __cdecl, unless you're using one of the old (Pocket PC 2000 or earlier) emulators, in which case it uses __stdcall (probably a misconfiguration when compiled...)

# New and Notable 33

Thursday, January 08, 2004 8:02 PM by Sam Gentile's Blog

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 5:50 PM by asdf
GCC has them, what are you talking about? http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#Function%20Attributes

Search for stdcall, cdecl, fastcall, etc.

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 9:09 PM by project
In "thiscall" you write that function names are decorated with information about every parameter in order to allow overloading. I think this should be also true about __cdecl functions that are not extern "C". Am I right?

# re: The history of calling conventions, part 3

Thursday, January 08, 2004 9:20 PM by Raymond Chen
You're right, I confused calling convention with C++ decoration. Sorry, everybody.

# Why do member functions need to be

Friday, January 09, 2004 10:01 AM by The Old New Thing

# re: The history of calling conventions, part 3

Friday, January 09, 2004 7:31 PM by CW user
Anyone using CodeWarrior?

When I had code like this:
#define EXPORT __declspec(dllexport)
EXPORT BOOL CALLBACK EdrCenterText(...)
the function GetProcAddress would return NULL.

But call like this:
GetProcAddress (..., "_EdrCenterText@16");
worked and I could use the DLL.

And then I changed the declaration to
EXPORT BOOL __cdecl EdrCenterText (...)
and
GetProcAddress (..., "EdrCenterText")
worked as advertised.

I do not have VC to check this but it all seems odd to me!

# re: The history of calling conventions, part 3

Friday, January 09, 2004 8:57 PM by project
To make the first GetProcAddress work, you should have a .def file like this:
EXPORTS
EdrCenterText

# re: The history of calling conventions, part 3

Saturday, January 10, 2004 12:55 AM by Raymond Chen
CW: The GetProcAddress issue is the subject that I alluded to in the opening paragraph of Part 2 of the calling conventions series. I'll expand on it in a future entry.

# re: The history of calling conventions, part 3

Saturday, January 10, 2004 9:01 AM by WC user
I've looked back to Part 2 and now I apologise if I've had spoiled
something, Raymond.

It was just something that bothered me since last summer when
it was for the first time I looked for some DLL stuff in Petzold and
then spent whole night to force GetProcAddress() return
something.

# re: The history of calling conventions, part 3

Saturday, January 10, 2004 9:10 AM by Raymond Chen
No problem. You couldn't have known. It's amusing to me that somebody guessed what I was referring to there completely by accident.

# re: The history of calling conventions, part 3

Monday, January 12, 2004 11:40 AM by Ben Combee
<blockquote>Anyone using CodeWarrior?

When I had code like this:
#define EXPORT __declspec(dllexport)
EXPORT BOOL CALLBACK EdrCenterText(...)
the function GetProcAddress would return NULL.</blockquote>

The problem is that you're not putting the "__declspec(dllexport)" on the function, but instead putting it on the type.

If you'd written

#define EXPORT __declspec(dllexport)
BOOL CALLBACK EXPORT EdrCenterText(...)

it would have been OK. I know -- I once was the x86 compiler engineer at Metrowerks, and I had my hand at implementing the declspec handling code.

# re: The history of calling conventions, part 3

Monday, January 12, 2004 3:10 PM by CW user
Seems like I could have asked if there's "Anyone here who wrote
CodeWarrior?"
Just shows how relevant Raymond's blog is.

And, no, reordering keywords didn't help. Still worked only with _ and
@16 mangling.

And as an interresting note, all this time I was casting to CALLBACK function pointer:
EXPORT BOOL __cdecl EdrCenterText (...);
typedef BOOL (CALLBACK *EdrCenterTextProcType) (...);
and then later in code:
EdrCenterTextProcType plugProc;
plugProc = (EdrCenterTextProcType) GetProcAddress (..., "EdrCenterText");

This code worked OK, even though I casted __cdecl proc to __stdcall
proc. I am not much of an expert for stack handling and calling
conventions, but I would like to know for sure if this is bad in any way.
(Windows or my app never crashed, but maybe I did't wait long
enough)

# re: The history of calling conventions, part 3

Monday, January 12, 2004 3:59 PM by Raymond Chen
You people are too fast for me. I have an entry planned for Thursday to discuss this.

# re: The history of calling conventions, part 3

Tuesday, January 13, 2004 10:31 AM by Raymond Chen
"does the virtual function table behave similarly to these jump to address and then jump to final address like the incremental linking comment above"

The jump-to-jump is an artifact of incremental linking and is not part of the vtable layout rules.

# Calling Convention

Tuesday, February 03, 2004 1:28 PM by Simply Patrick
??????,??????????? ?????????? calling convention: The history of calling conventions, part 1 The history of calling conventions, part 2 The history of calling conventions, part 3 The history of calling conventions, part 4: ia64 Why do member functions need to be...

# re: The history of calling conventions, part 3

Thursday, May 27, 2004 6:52 AM by Benjamin Munayco
Hi,

PVCAM is an ANSI C library of camera control and data acquisition functions.
I'm trying to use PVCAM functions on my computer running under Windows XP but I didn't manage to.
The problem occures when I run the project in my CodeWarrior IDE which is the programming environment I choose in order to compile my
project.
The compiling process works well, but when I link the project that's the message I'm given back:

" Error : Undefined symbol: '__stdcall(0) pl_pvcam_init
(_pl_pvcam_init@0)'
referenced from '_main' in Acquisition.c:15
Acquisition.c line 15 "

("Acquistion.c" is my C code source)

and I get the same error for each PVCAM functions (pl_pvcam_uninit, pl_seq_exp, etc.)
I am a beginner in programming on CW 8, and I don't really know where to search the problem.
This could be due to the linker, the IDE, a confusion between libraries...
Could you help me with this topic?

Thanks.

# Diagnosing a problem with calling conventions

Tuesday, July 06, 2004 10:02 AM by The Old New Thing
Putting together some skills you've already learned.

# The history of calling conventions

Wednesday, July 07, 2004 11:03 PM by Flier's Sky
The history of calling conventions

# Using the Profiling API Enter/Leave Function Hooks

Thursday, August 11, 2005 3:20 PM by Jonathan Keljo's CLR Blog
Ever since v1, corprof.idl has contained the following ominous comment above the typedefs for FunctionEnter/Leave/Tailcall....

# Using the Profiling API Enter/Leave Function Hooks

Thursday, August 11, 2005 4:47 PM by Jonathan Keljo's CLR Blog
Ever since v1, corprof.idl has contained the following ominous comment above the typedefs for FunctionEnter/Leave/Tailcall....

# Using the Profiling API Enter/Leave Function Hooks

Monday, August 15, 2005 2:55 PM by Jonathan Keljo's CLR Blog
Ever since v1, corprof.idl has contained the following ominous comment above the typedefs for FunctionEnter/Leave/Tailcall....

# Using the Profiling API Enter/Leave Function Hooks

Sunday, September 11, 2005 2:13 PM by Jonathan Keljo's CLR Blog
Ever since v1, corprof.idl has contained the following ominous comment above the typedefs for FunctionEnter/Leave/Tailcall....

# The history of calling conventions

Wednesday, May 17, 2006 8:44 AM by Anuncie Aqui!
New Comments to this post are disabled
 
Page view tracker