Reputation: 486
First I'm going to demonstrate a poor understanding of the stack, and then I'm going to ask a mildly coherent question that can't be answered well because the question isn't specific enough to elicit a well-composed answer.
So, when a program runs functions are pushed to the stack - this means the stack pointer is incremented or decremented?
What exactly is stored in the stack memory allocation? Pointers to variable data, pointers to the est of the program? I just don't understand what exactly is stored on the stack (what data types, what kinds of references, how they ae stored) I expect a function stores its local variable pointers and a pointer to the address that called it so it can return.
Also, windows x86 virtual memory allocation actually maps a single block of virtual memory to arbitrary many physical memory addresses, so a stack is or is not contiguous in the physical memory of a windows x86 system?
Finally, assuming a stack is stored in the user-allocated virtual memory of an application on 32-bit windows on x86, the stack pointer (which references the high or low memory address?) is a 31-bit (31 because user-allocated and the high 2GB are reserved for kernel allocated) little-endian reference, right?
And when data reaches the stack (like a function is entered and allocates memory for a new DWORD) the data to store in that DWORD is pushed to the stack and the stack pointer is incremented or decremented? And how is the system aware of both ends of the stack simultaneously?
---- ESP HERE?
|-reference address for variable x
|-integer data to be stored in the memory address of variable x in function 1
|----function 1 block above ^^
|
|
---- OR ESP HERE?
And from here the reference address and integer data will be popped into registers, and a mov operation will store the integer data at the allocated memory location?
When new data hits the stack, I've heard the stack grows "downward" but that seems irrational since there are only higher and lower memory addresses - I understand that only one end of the stack needs to be incremented/decremented, but is it the high or the low address, and how is the stack length(height) delimited? How does the system understand when the stack has "grown" too large?
Sorry for all the questions, but I've been doing a lot of reading, and the terminology used to describe the concepts I've been reading about aren't well operationalized in my vocabulary. Also I checked a bit around google, wikipedia, and this site and couldn't find an explanation that addressed my specific concerns.
Thanks.
Upvotes: 1
Views: 1632
Reputation: 12515
Ok. A stack is just an abstract data type. Good. An array of memory that you can place (puhs) data onto the end of and remove (pop) it back off. Grows up or down, off the front or back, or whatever depending on how its implemented. Good.
Now the (a) system stack is a bit more defined. It is an area of RAM allocated by the program, or local thread storage or whatever. The pointer is placed at the "end" of its memory location and it grows back towards the top. A push places data onto the stack at its current location (minus the data size so that it doesn't go past the end), so decrement before write. When compelte, the new stack pointer points to the start of the last "pushed" value.
Why backwards? Convention and ease of use. Consider an embedded system or some older system with more limited RAM resources. If we have the Heap start towards the top of RAM - just after the code and static/const data and we need another type of storage in the same RAM space, why not have it grow from the back? This way you need not worry about how big each section has to be. They will meet in the middle somewhere when all RAM has been used (and the next write will go boom, via stack overflow.) Easy to maintain and create and efficient - no guessing about proper sizes and such.
Just start here. Virtual addresses and such shouldn't worry you too much at this point. They just help with the "go boom" part when and if you run out of space. I doubt the stack is ever split across multiple pages, but if it is, let the OS handle it and all is well (and slow, but that's another story.)
Now what goes on a stack - whatever you want. Typically, parameter passed to functions that go beyond what can fit into registers, scoped variables that aren't needed beyond a function, c++ glue for this pointers on occasion, and sometimes more when using alloca()
to treat stack like dynamic memory - you'll see this in thread code often to help prevent memory write race conditions and such. Also, values returned by value that won't fit within registers are typically returned on the stack as well. Basically, every local var you see in a function has a strong chance of living on the stack at some point as registers fill up and more space is needed. Hence, many systems try to make sure that stack memory is as fast as possible.
To answer your remaining questions - the system may or may not be aware of both sides of the stack - depends on the platform. I'm guessing windows is aware of the stack start via tracking if a write geos out beyond an end. Unpaired push/pops will ruin a program's day and sometimes bring an OS hang as well (less so now days). I cannot answer your windows specific 32/31 bit address question as I have no direct experience there. Someone else can grab that part. Finally, stacks growth direction is confusing terminology. I usually think of system stack as growing "upwards", but that may be just me.
Hope this helps and clears up some issues for you!
Upvotes: 3
Reputation: 180777
when a program runs functions are pushed to the stack - this means the stack pointer is incremented or decremented?
That depends on how the stack is implemented. If it grows from the end of memory backward, it is decremented. If it grows from the beginning of memory forward, it is incremented.
What exactly is stored in the stack memory allocation?
Whatever a given program or programming language pushes onto the stack. This can include return addresses, value types, pointers to objects, and stack frames.
windows x86 virtual memory allocation actually maps a single block of virtual memory to arbitrary many physical memory addresses, so a stack is or is not contiguous in the physical memory of a windows x86 system?
See here: http://www.dirac.org/linux/gdb/02a-Memory_Layout_And_The_Stack.php
How does the system understand when the stack has "grown" too large?
It hits the top of the heap.
Upvotes: 1