CallingConventions

From HerzbubeWiki
Jump to navigation Jump to search

This page currently has details about calling conventions on the x86 platform only. The focus is on calling conventions encountered while programming in the Windows world.


What are calling conventions

Direct quote from the Wikipedia article:

A calling convention is a scheme for how subroutines receive parameters from their caller and how they return a result; calling conventions can differ in:

  • Where parameters and return values are placed (in registers; on the call stack; a mix of both)
  • The order in which parameters are passed (or parts of a single parameter)
  • How the task of setting up for and cleaning up after a function call is divided between the caller and the callee
  • Which registers that may be directly used by the callee may sometimes also be included (otherwise regarded as an ABI-detail).
  • Which registers are considered to be volatile v. non-volatile and, if volatile, need not be restored by the callee

Different programming languages use different calling conventions, and so can different platforms (CPU architecture + operating system).


References


Varargs

When the callee cleans the arguments from the stack it needs to be known at compile time how many bytes the stack needs to be adjusted. Therefore, calling conventions that belong to the "callee clean-up" category are not compatible with variable argument lists (e.g. printf()).


Calling conventsions

stdcall

  • stdcall is a calling convention on the x86 platform
  • __stdcall is used by the entire Windows API! The preprocessor macro WINAPI, often seen to mark Windows API functions, resolves to __stdcall. Note that strictly speaking one should not rely on the fact that WINAPI resolves to __stdcall - it's an implementation detail that might change "any time".
  • stdcall is "Callee clean-up" (e.g. varargs are not possible)
  • The VC++ compiler marks up stdcall functions with the keyword __stdcall


cdecl

  • cdecl is a calling convention on the x86 platform
  • cdecl originates from the C programming language, hence its name
  • cdecl is the standard calling convention for functions in C, and non-member and static member functions in C++. Despite this "standard", different compilers have different interpretations of how cdecl should be implemented. If the same program is compiled with 2 different compilers, or the same compiler but on 2 different OS platforms, the 2 compilation results may very well be incompatible.
  • cdecl is "Caller clean-up" (e.g. varargs are possible)
  • The VC++ compiler marks up cdecl functions with the keyword __cdecl


Note: The use of extern "C" in C++ code (to prevent name mangling) is not directly related to the use of cdecl (or any other calling convention), and the two concepts should not be mixed. It's just a "coincidence" that extern "C" is usually applied to global C-style functions and that those functions by default use the cdecl calling convention.


thiscall

  • thiscall is used for calling C++ non-static member functions
  • The name of the calling convention stems from the fact that behind the scenes the compiler adds an argument to the function parameters that contains the this pointer, i.e. the pointer to the C++ object that receives the method call
  • There are different versions of thiscall, depending on the compiler (e.g. GCC, VC++) and also on whether or not the member function being called uses variable arguments
  • thiscall is both "Caller clean-up" and "Callee clean-up", depending on the use of varargs by the member function being called
  • The VC++ compiler marks up thiscall functions with the keyword __thiscall


Calling conventions and VC++

General notes

  • In a VC++ project, if a a function does not have an explicit calling convention it uses the default calling convention defined for the project (or the file)
  • In Visual Studio 2010 the project-wide default can be found in the project's properties dialog under "Configuration Properties > C/C++ > Advanced > Calling Convention"
  • If the project does not explicitly set a a calling convention, it inherits the default __cdecl


Function declarations

This is the syntax for declaring a function prototype with a calling convention:

ReturnType CallingConvention FunctionName(ParameterList);

Example:

int __stdcall DoIt(const char* foobar);


Function pointers

If a function pointer is defined (e.g. for callback functions, or if LoadLibrary() or GetProcAddress() is used), it also requires that a calling convention is used for the function pointer type declaration.

Example:

typedef int (__stdcall *FUN_DoIt) (char* foobar);


P/Invoke

If a native function is invoked from .NET via P/Invoke, the P/Invoke declaration needs to include the calling convention. If the calling convention is omitted, the default is CallingConvention.Winapi (which at runtime resolves to different calling conventions, depending on the platform that the code is executing on).

Example:

[DllImport("kernel32.dll", SetLastError=true, CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool Beep(uint dwFreq, uint dwDuration);