![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Programmer
Join Date: Sep 2005
Posts: 33
Rep Power: 0
![]() |
stack query
can anyone explain how the local variables are acessed from a stack frame of that particular function..since stacks can only push or pop values and stack pointer always points to top of the stack and the frame pointer always points to the end of the previous stack frame..how local variables are acessed?
for eg: suppose for func temp int temp(int a,int b); { int d=10; int e,f,g; e = d; g = e+d; f=g; return(1); } first b will be pushed then a then the return address and the then stack frame for the func temp will start..and d,ef,g will be pushed in..but then how are these local variables acesses for assignment when only way they can come out by popping.. may be im not able to explain in proper way but can anyone if possible explain this... |
|
|
|
|
|
#2 |
|
Expert Programmer
Join Date: Jun 2005
Posts: 877
Rep Power: 4
![]() |
Different systems will do it different ways, but basically the compiler knows what offset each of the variables is from the stack frame.
In your example: b is at stack frame - 3 * sizeof int a is at stack frame - 2 * sizeof int return address is at stack frame - 1 * sizeof int d is at stack frame e is at stack frame + 1 * sizeof int f is at stack frame + 2 * sizeof int g is at stack frame + 3 * sizeof int So the compiler would keep the stack frame address in the frame pointer (probably the previous value would be pushed on the stack before calling the function). Then each access to a local variable becomes and access to a memory location that is the frame pointer + or - and offset. Note that on many systems the stack grows downward, so the +'s and -'s would be the other way round. |
|
|
|
|
|
#3 |
|
Expert Programmer
Join Date: Jun 2005
Posts: 877
Rep Power: 4
![]() |
Actually there is another strategy which doesn't need the frame pointer to point to this frame.
The compiler knows how many items are allocated on the stack in this function, so each variable can just be offset from the current stack pointer. e.g. g is at stack pointer - 1 * sizeof int f is at stack frame - 2 * sizeof int etc. Even though it looks in C like the variables are just pushed on the stack when you declare them, what normally happens is that the compiler works out how much space it needs for the whole function and allocates that much at the start of the function. Note that this method makes the compiling more complex when you are calling other functions as you have to take into account how many extra parameters you have pushed on to the stack at any point. It is likely that my first answer is what is used more commonly. |
|
|
|
|
|
#4 | |
|
Newbie
Join Date: Sep 2005
Location: Mumbai (Bombay)
Posts: 9
Rep Power: 0
![]() |
Quote:
|
|
|
|
|
|
|
#5 |
|
Programmer
Join Date: Sep 2005
Posts: 33
Rep Power: 0
![]() |
Thanks Dark for your replies and explanations...
building up to your explanation here is a link that explains the stuff in detail. http://www.unixwiz.net/techtips/win32-callconv-asm.html |
|
|
|
|
|
#6 |
|
Resident Grouch
![]() ![]() ![]() ![]() ![]() ![]() Join Date: Jun 2005
Posts: 6,453
Rep Power: 10
![]() |
As with any generic explanation, one may find points to quibble with, here, or exceptions. That's a given. The C/C++ language doesn't even require that a stack be used for the passing of arguments to functions. Nevertheless, if you have a general idea of how the stack method works (and it's used in a LOT of implementations), you understand some things immediately, that you might not have fully understood before. Why do "local" variables "disappear" when the function returns? Why does overwriting a buffer (as with "gets", for example) represent a possible trashing of valuable content and even a potential secutity problem? All in the mechanism.
GENERIC STACK-USAGE METHOD
Most microprocessors have an internal pointer (the stack pointer) which
references memory so that the micro can keep track of the point of execution
as it varies because of interrupts, function calls, and so forth. The stack
(memory to which it points) is also used by many systems (sometimes
unfortunately) as a storage place for local values, saved registers, and so
forth.
Just prior to a call, the stack pointer, which is much like any pointer one
defines, is pointing to some place in memory (designated by the programmer
or the operating system) for its use. When you call a function, it works
something like this (its usage varies somewhat from language to language --
even within one language).
stack pointer -->| orig position | In most systems, the stack pointer moves toward
| | lower addresses as you use it.
~ ~
At call: | orig position |
| arguments |
stack pointer -->| last argument |
| |
| |
| |
| |
~ ~
There may be zero or more arguments. They are pushed onto the stack in a predetermined order. For C/C++, it is right-to-left. The stack pointer moves with each push.
After call: | orig position |
| argument here |
| (maybe more)
stack pointer -->| ret addr here |
| |
| |
| |
~ ~
Into procedure | orig position |
Arguments avail | arguments... | When you modify the argument(s), you modify
for use | ret addr here | the value(s) stored here. If an argument
| saved regs, | is a reference or pointer you may use it to
| locals, etc. | modify the value pointed to elsewhere
| in this area | (in the calling procedure, say). If you write
stack pointer -->| | more data to one of the local variables than it
~ ~ can store, guess where the excess winds up.
The function does its work and unwinds the stack (locals, etc.)
Before return | orig position | Immediately before the return, after storage
| arguments... | for saved registers, locals, etc. has already
stack pointer -->| ret addr here | been recovered (and disappeared). The arguments
| | are still on the stack.
| |
| |
~ ~
After return: | orig position | Immediately after the return. The very first
stack pointer -->| arguments... | thing the machine is going to do next is destroy
| | the arguments, whether you've modified them or not.
| | Sometimes the arguments are removed by the called
| | function and the return address position adjusted
| | appropriately.
~ ~
stack pointer -->| orig position | And it's done; you are right back where you started,
| | bookkeeping wise, when you made the call. Any
| | changes you made to the arguments are history, for
~ ~ all practical purposes (they may persist until the
next stack operation).
If you passed an argument as a reference, any modifications you made to the value it
referred to are, of course, in force. If you modified the reference, itself, to point
to something else, you could modify that something else, also (for example, subsequent
bytes pointed to by a char *). The reference itself disappears. If you pass
an argument by value, that value is perfectly usable to the called procedure;
it could specify a length to use for some operation, for example. If you
modify the value, such modifications disappear when the arguments
disappear, immediately after the called procedure returns to the caller. If you
want lasting changes in the caller, you need to make them by reference or
RETURN a value from the called procedure.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code. Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers |
|
|
|
|
|
#7 |
|
Newbie
Join Date: Sep 2005
Location: Cambridge, UK
Posts: 13
Rep Power: 0
![]() |
Just a quick query here guys - sorry if im hogging your thread!
Where i'm from (embededd environments) (and please correct me if i'm wrong because i am rusty) in Aloksaves function temp() there is no reason for a stack to be used at all apart from the return address when temp has finished. Temp variables will be assigned to registers and since there is no function calls within temp() - there will not be a push to the stack with the locals on it because there is no point. My question is - what environment are locals created on the stack even if they are not used other than anywhere locally ? (like in temp() above). Thanks Ringo |
|
|
|
|
|
#8 |
|
Programmer
Join Date: Sep 2005
Posts: 33
Rep Power: 0
![]() |
All the variables created in C are created on the stack unless if they are created dynamically(go on to the heap) or they are declared global or static (go on to the data segment and BSS...Data segment contains static, global initialized variables and BSS contains static, global uinitialized variables)
Is what I say correct...Somebody Please confirm |
|
|
|
|
|
#9 |
|
Newbie
Join Date: Sep 2005
Location: Cambridge, UK
Posts: 13
Rep Power: 0
![]() |
What development environment are you talking about dude ?
Anyway, i may have been incorrect - not completely, but a bit: A compiler can allocate variables to the stack or to a register (if it's only used locally) - that is the compilers choice. I am used to programming in an environment where memory is expensive (not so true now but where physical size is an issue (ie cell phones) its still holds) and efficient code is paramount - embedded software or thereabouts. Anyway, i wouldn't really be very happy if a compiler decided to put a temp variable on the stack - thats what registers are for. HOWEVER, i have no experience in other environments - so your words may be correct for your circumstances. Just be careful - "All variables created in C are created on the stack". It's nothing to do with C - its to do with the compiler. As i said before, sorry for hogging your thread and sorry for not providing an answer to your original question. |
|
|
|
|
|
#10 | |
|
Programming Guru
![]() Join Date: Oct 2004
Location: namespace std
Posts: 1,246
Rep Power: 6
![]() |
Quote:
i don't know about you but i'd be hard-pressed to fill up the 160 Gb of ROM that i have. seriously, do people just have libraries of movies on their computer? wtf!?!
__________________
i put on my robe and wizard hat... Have you ever heard of Plato, Aristotle, Socrates?...Morons. |
|
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|