|
 |
Assembly Language
What every pc speaks..1010... |
|
|
|
Calling Functions...
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.
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:
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 |
|
|