I am trying to understand how stack frames are built and which variables (params) are pushed to stack in what order? Some search results showed that the C/C++ compiler decides based on operations performed within a function. For example, if the function was supposed to just increment a passed-in int value by 1 (similar to ++ operator) and return it, it would put all the parameters of the function and local variables into registers.
I'm wondering which registers are used for returned or pass by value parameters. How are references returned? How does the compiler choose between eax, ebx,ecx and edx?
What do I need to know to understand how registers, stack and heap references are used, built and destroyed during function calls?
-
this is rather hard to read (wall of text). Would you mind editing your post into a better shape?gnat– gnat2013年04月18日 17:00:52 +00:00Commented Apr 18, 2013 at 17:00
-
1This question seems rather broad to me. Also, isn't this going to be very platform-specific?Kazark– Kazark2013年04月18日 17:21:40 +00:00Commented Apr 18, 2013 at 17:21
-
Question was also asked on SO: stackoverflow.com/questions/16088040/…Wayne Conrad– Wayne Conrad2013年04月18日 17:26:51 +00:00Commented Apr 18, 2013 at 17:26
-
See also my answer on SOBasile Starynkevitch– Basile Starynkevitch2013年04月18日 17:39:17 +00:00Commented Apr 18, 2013 at 17:39
4 Answers 4
In addition to what Dirk said, an important use of stack frames is to save previous values of registers so that they can be restored after a function call. So, even on processors where registers are used for passing parameters, returning a value, and saving the return address, the values of those registers are saved on the stack before a function call so that they can be restored after the call. This allows one function to call another without overwriting its own parameters or forgetting its own return address.
So, calling a function B from function A on a typical "generic" system might involve the following steps:
- function A:
- push space for the return value
- push parameters
- push the return address
- jump to the function B
- function B:
- push the address of the previous stack frame
- push values of registers that this function uses (so they can be restored)
- push space for local variables
- do the necessary computation
- restore the registers
- restore the previous stack frame
- store the function result
- jump to the return address
- function A:
- pop the parameters
- pop the return value
This is by no means the only way function calls can work (and I may have a step or two out of order), but it should give you an idea of how the stack is used to let the processor handle nested function calls.
-
What does "push" exactly mean here? I have no idea what to make of it.Tomáš Zato– Tomáš Zato2017年01月09日 20:12:27 +00:00Commented Jan 9, 2017 at 20:12
-
4@TomášZato
push
andpop
are the two fundamental operations on a stack. A stack is a last-in-first-out structure, like a stack of books. When youpush
, you're putting a new object on top of the stack; when youpop
you're taking an object from the top of the stack. You're not allowed to insert or remove objects in the middle, you can only operate on the top of the stack. You might read more about stacks generally and the program stack in particular on Wikipedia.Caleb– Caleb2017年01月10日 02:49:38 +00:00Commented Jan 10, 2017 at 2:49 -
Why would you push address of previous stack frame if you do not use it anywhere in procedure descibed by you?Trismegistos– Trismegistos2020年12月23日 08:47:03 +00:00Commented Dec 23, 2020 at 8:47
-
@Trismegistos You push the previous stack frame base pointer so that you can restore it when you're done. The caller needs its stack frame set up just as it was when it made the call, and you can't restore the previous stack frame base pointer if you don't save it somewhere.Caleb– Caleb2020年12月23日 16:58:16 +00:00Commented Dec 23, 2020 at 16:58
This depends on the calling convention being used. Whoever defines the calling convention can make this decision however they want.
In the most common calling convention on x86, registers aren't used for passing parameters; the parameters are pushed on to the stack starting with the rightmost parameter. The return value is placed in eax and can use edx if it needs the extra space. References and pointers are both returned in the form of an address in eax.
If you understand stack very well then you will understand how memory works in program and if you understand how memory works in program you will understand how function store in program and if you understand how function store in program you will understand how recursive function works and if you understand how recursive function works you will understand how compiler works and if you understand how compiler works your mind will works as compiler and you will debug any program very easily
Let me explain how stack works:
First you have to know how function store in stack :
Heap store dynamic memory allocation values. Stack store automatic allocation and deletion values.
Let's understand with example :
def hello(x):
if x==1:
return "op"
else:
u=1
e=12
s=hello(x-1)
e+=1
print(s)
print(x)
u+=1
return e
hello(4)
Now understand parts of this program :
Now let's see what is stack and what are stack parts:
Allocation of the stack :
Remember one thing if any function get "return" no matter it have loaded all his local varibles or anything it will immediately return from stack will his stack frame. It means when any recursive function get base condition and we put return after base condition so base condition will not wait to load local variables which are situated in "else" part of program it will immediately return current frame from the stack and now if one frame return next frame is in activation record. See this in practical:
Deallocation of the block:
So now whenever a function found return statement it delete current frame from the stack.
while returning from the stack value will return in reverse order of order in which they allocated in stack.
These are very short description and if you want to know more deep about stack and double recursion read two post of this blog :
What you are looking for is called Application Binary Interface - ABI.
There is a specification for each compiler that spells out the ABI.
Each platform will usually specify and ABI on order to support interoperability between compilers. For example, x86 Calling Conventions spells out the typical calling conventions for x86 and x86-64. I would expect a more official document than wikipedia however.