In C++ FAQ:
Assuming a typical C++ implementation that has registers and a stack,
the registers and parameters get written to the stack just before the
call to g(), then the parameters get read from the stack inside g()
and read again to restore the registers while g() returns to f().
regarding the nested function call
void f()
{
int x = /*...*/;
int y = /*...*/;
int z = /*...*/;
...code that uses x, y and z...
g(x, y, z);
...more code that uses x, y and z...
}
1/ Are all implementation of C++ with registers and stack? Does it mean: implementation dependent on compiler/processor/computer architecture?
2/ What is sequence of instructions (without assembly language, just the big picture) when i call f()
? I have read diverging things on this topic, and also I don't remember that registers where mentionned, but only stack.
3/ what are additional specificities/points to underline when you deal with nested functions?
thanks
For number 2
this depends on many things including the compiler and the platform. Basically the different ways of passing and returning arguments to functions are called calling conventions. the article Calling conventions on the x86 platform goes into some detail on sequence of operations and you can see how ugly and complicated it gets with just this small combination of platforms and compilers which is most likely why you have heard all sorts of different scenarios, The gen on function calling conventions. covers a wider set of scenarios including 64 bit
platforms but is harder to read. It gets even more complicated because gcc
may not actually push
and pop
the stack but directly manipulate the stack pointer, we can see an example of this, albeit in assembly here. It is hard to generalize about calling conventions, if the number of arguments is small enough many calling conventions can avoid using the stack
at all and will use registers
exclusively.
As to number 3
, nested functions does not change anything, it will just repeat the procedure over again for the next function call.
As to number 1
As Sean pointed out .Net
compiles to byte code with performs all it's operations on the stack. The Wikipedia page on Common Intermediate Language has a good example.
The x86-64 ABI
document is another great document if you want to understand how one specific calling convention works in detail. Figure 3.5 and 3.6
are neat since they give a nice example of a function with many parameters and how each parameter is passed using a combination of general purpose registers
, floating point registers
and the stack
. This sort of nice diagram is a rare find when looking at documents that cover calling conventions.
1.
Although register/stack implementations are the most common underlying implementations of a C++ compiler there's nothing to stop you using a different architecture. For example, you could write a compiler to generate Java bytecode or .NET byte code, in which case you'd have a stack based C++ compiler.
2.
When you call f() the typical approach is:
Push the return address on the stack and jump to f()
In f():
Allocate space for the locals x,y and z. This is normally done on the stack. Take a look at this article on call stacks.
When you get to g(x,y,z) the compiler will generate code to push the values onto the stack by accessing their values in the stack frame of f(). Note that C/C++ pushes parameters from right to left.
When you get to the end of f() the compiler inserts a return
instructions. The top of the stack has the address to return to (it was pushed prior to the call to f() )
3.
There's nothing special about nested functions as everything follows the same basic template:
- To call a function - push parameters and call the function.
- Within the function - allocate space for local variables within a stack
Now this is the general approach. Compilers will introduce their own optimizations to improve performace. For example a compiler may choose to store the first 2 parameters in registers (for example).
NOTE: Although parameter passing by the stack is by far the most common approach there are others. Take a look at this article on register windows if you're interested in finding out more.