www.xbdev.net xbdev - software development
Sunday October 22, 2017
home | about | contact | Donations

     
 

Assembly Language

What every pc speaks..1010...

 

Calling Functions...



Necessity

Now at some point when writing C or C++ code you've come across those funny things in front of functions..e.g. __stdcall or possibly __cdecl.  Have you ever wondered what they are for?  Well its all to do with the calling convention of a function.  The windows API uses the __stdcall for its Win32 API's.  Hopefully this mini Tutorial will clear some points that you may have... and show you the inner workings of function calls.  I used Visual C++ to compile most of my demo's, but most if not all C/C++ compilers should follow this calling convention.

Which are Calling Conventions

A Calling Convention is a definition like a function....how parameters are passed and returned ...this is mostly accomplished using the stack.  But then comes the details of the order of passing the variables on the stack, and who is responsible for tidying the stack up afterwards.  In a program the Calling Conventions is not usually so important - but for communication over program borders (e.g. to the re-entry point in DLL) however a generally accepted definition is necessary!
Under Windows there are fundamentally three Calling convention ( __cdecl, __stdcall and __fastcall) and are exaplaned below in the following table:

 

__ cdecl

(C calling convention)

Function names are 'decorated' with a prefixed underscore character '_'

Parameter from right to the left are placed on the stack.

Stack cleanup is performed by the caller. (not the function)

(This is the default calling convention for C/C++ programs)

When calling a function, inside the function, the registers ESI, EDI, EBX and EBP are saved on the stack - and is usually generated by the compiler.  So in most cases you'll find a prolog and a epilog that saves and restores these registers.

 

An Example Function:

// __cdecl example function

int __cdecl sum(int a, int b)

{

      return a+b;

}

Calling the function:

// Calling it in C looks like this:

int r = sum(1, 2);

 

// Calling it in assembly

; push arguments onto the stack from right to left

push  2

push  1

 

; call our function

call  _sum

 

; cleanup the stack by adding the size of the arguments to the ESP registerr

; (where ESP is the 32 bit stack pointer registerr)

add         esp, 8

 

; save our returned value into a memory location

mov         dword ptr[r], eax

Function in Assembly:

// Assembly code for the function example function would look like this:

; function prolog.

push      ebp                       ; Function pro log

mov       ebp,  esp               ; Function pro log (Stackframe)

 

; return a+b

mov         eax,  dword ptr[a]

add         eax,  dword ptr[b]

 

; function epilog.

pop         ebp                       ; Restore old Stackframe

ret

 

 

__ stdcall

(Standard calling convention)

Parameter from right to the left on the stack - function clears up the stack

Stack cleanup is performed by the called function.

The Function name is 'decorated' by a prepending an underscore character at the front of the funciton name, and appending a '@' character to the end..WITH the number of bytes of stack space required.

 

Since windows API's use the __stdcall convention, if you look deep inside the header files you'll find this:

 

#define WINAPI __stdcall

 

As so often programmers get used to using WINAPI for function prototypes....but forget what it actually is.

 

An Example Function:

// __stdcall example function

int __stdcall sum(int a, int b)

{

      return a+b;

}

 
Calling our function:

// Calling it in C looks like this:

int r = sum(1, 2);

 

// Calling it in assembly

; push arguments onto the stack from right to left

push  2

push  1

 

; call our function

call  _sum@8

 

; save our returned value into a memory location

mov         dword ptr[r], eax

 
Representing our function in Assembly:

// Assembly code for the function example function would look like this:

; function prolog.

( Same as __cdecl)

 

; return a+b

mov         eax,  dword ptr[a]

add         eax,  dword ptr[b]

 

; function epilog.

( Same as __cdecl)

 

; cleanup the stack

add         esp,  8

 

; On some assemblers, you might see

; ret 8

; Which restores the stack then returns :)

 

; return from our function

ret

 

 

An interesting thing to notice with __stdcall, is that we can't pass a variable number of arguments to the function, as you can with __cdecl... an example of where you do this is with printf(..).  This is because the function is doing the cleanup, and doesn't know how many variables your passing, but with __cdecl, the caller does the cleanup so it knows how many variables where pushed on the stack.

 

 

 

__fastcall

(Fast calling convention)

First two parameters passed to the function are passed using registers ECX and EDX.  The rest of them are pushed on the stack from right to left.

The function is responsible for cleaning up the stack.

Function name is 'decorated' by prepending a '@' character at the front of the function name, and appending a '@' on the end,... WITH the number of bytes (decimal) of space required byt the arguments.

 

An Example Function:

// __fastcall example function

int __fastcall sum(int a, int b)

{

      return a+b;

}

Calling our function:

// Calling it in C looks like this:

int r = sum(4, 3);

 

// Calling it in assembly

; push arguments onto the stack from right to left

mov         ebx,  4

mov         ecx,  2

 

; call our function

call  @sum@8

 

; save our returned value into a memory location

mov         dword ptr[r], eax

Representing the function in Assembly:

_a$ = -4
_b$ = -8

 

// Function code in Assembly Language

; function prolog.

push       ebp                       ; Function pro log

mov        ebp,  esp               ; Function pro log (Stackframe)

 

pop         ecx

mov        DWORD PTR _b$[ebp], ebx

mov        DWORD PTR _a$[ebp], ecx

 

; return a+b

mov         eax, DWORD PTR _a$[ebp]

add         eax, DWORD PTR _b$[ebp]

 

; function epilog.

mov         esp, ebp               ; Restore old stack

pop         ebp                      ; Restore old Stackframe

ret          0

 

 

So is __fastcall any faster?  Well in certain situations yes... but your free to test it out yourself.

 

Thiscall Arguments are passed from right to left on the stack.  The this pointer is placed in ECX.

Stack cleanup is performed by the calling function.

 

Its the default calling convention for C++ compilers.

 

[ Now if a variable number of arguments have to be passed - in that case __cdecl would be used, and this pointer would be pushed on the stack last. ]

__ pascal Parameter from left to the right on the stack - function clears up the stack
__ nearly call First the parameters in registers are assigned - then the stack is used.


 

 

Return values:
 

8 bits of values in the register AL
16 bits of values in the register AX ,
32 bits of values in the register EAX

 

 

 

 

 

 

 
 Visitor: 9534626  { 209.237.238.175 } Copyright (c) 2002-2017 xbdev.net - All rights reserved.
Designated tutorial and software are the property of their respective owners.