This is a mini tutorial (two pages) on calling conventions and what they are do, and is relevant to writing dlls in C and C++ as well as using them from C#. This may be useful in understanding the skeleton code provided for creating dlls in Ongoing Programming Challenge #1.
If you are unfamiliar with the concepts of Compiling and Linking then you should read these articles first.
Note- this is not about linking but using dlls and calling them at runtime.
A calling convention defines how parameters are passed on the stack and whether the caller or the function has to tidy up the stack after the call.
About Stacks
A stack tracks where a function was called from. This is usually implemented in hardware by using a register which is a pointer into a block of memory. Traditionally a stack starts pointing to the end of a block of ram. As each item is pushed on the stack, the stack pointer is decremented. When you remove something from the stack (popping it off) the stack pointer is incremented. You must ensure that for every push there is an equal pop if you write in assembler but C and C++ take care of this.There are usually compiler settings to specify how much ram is made available for the stack.
Stacks can hold three types of thing.
- Return Addresses.
- Function Parameters.
- Local Variables.
Return Address
When a function is called, the first thing the CPU has to do is work out what the next instruction will be when the called function exits. The table below shows a simplified version of what is happening.Address 101In the above example, if the CPU has just processed the instruction at 101, its next operation will be to process the instruction at address 102 and call the function at 201. After that exits the next instruction will be 103. It will then carry on until 151 when it again calls the function at address 201. This time when it returns, it carries on with the instruction at 152. The addresses 103 and 152 are the return addresses that are stored on the stack.
Address 102 Call Function 201
Address 103...
...
Address 151 Call Function 201
Address 152...
Address 201.. First instruction of function
Address 202.. Allocate memory for local variables
...
Address 206.. Release the allocated memory
Address 207.. return from function
Stack State If the stack starts with a pointer to 5000 then this is what it will look like as the example above is processed.
Stack Pointer= 5000When function 201 is called and after the instruction at 202 has run, the stack will now have data there. Let's imagine that this function has no parameters but has a local variable totals which is an array of 10 ints.
Address 5000
int totals[10]If each address holds one int then this array is 10 locations in size. At 201 the stack pointer will be decremented by 10.
Stack Pointer= 4989When 206 is executed the stack pointer will be incremented by ten. The instruction at 207 will pop the top of the stack. Popping is the opposite of pushing. With a push a value is stored at the current address held in the stack pointer then the stack pointer is decremented. Popping increments the stack pointer by 1 then gets the value from the address held in the stack pointer. So this gets the value from address 5000 which is 103 and that's the next instruction to be executed.
Address 5000 .. 103
Address 4999 .. total[9]
Address 4998 .. total[8]
...
Address 4990 .. total[0]
Address 4989 <- Current top of stack.
Pass By Value or Pass By Reference?
Pass by Value copies the entire variable onto the stack and this is not only slow but if the variable is big, it can blow the stack. E.g. a 10,000 int array will decrement the stack pointer by 10,000 and copy each of the 10,000 int values in to the stack! It's much faster to use Pass by Reference when just the address of the variable is pushed on the stack. So in C use pointers (*) and in C++ references (&) to keep it lean and mean.Calling Conventions
It's important to know- with parameters e.g. a,b,c, are they pushed on the stack in that order or c,b,a and where does the return address go? Also, does the called function remove parameters from the stack or does the main program? Why not pass values in registers to speed things up? Specifying what happens is what calling conventions do.Next Page - List of Conventions plus Name Mangling in C++

