简体   繁体   中英

How does Stack memory work Or How are function variables allocated and accessed on the stack

When I read about Stack and Heap for example on this page ,
I had one question, if, like in the example given on the page, a functions puts all its local variables on the stack, does the stack actually access the different variables?
Because a stack normally only can access the top, it would only be able to access ONE variable of the function.
Does this imply that variables of a function are stored in a struct on the stack?

The stack-pointer is, like its name implies, a pointer like any other, and it points to normal standard memory. To access any area of the stack you simple add an offset to the pointer.

If you think of it in terms of C pointers, you have the stack pointer

char *stack_pointer = some_memory;

This pointer can then be used as a normal pointer, including adding offsets to access specific locations on the stack, like eg

*(int *)(stack_pointer + 4) = 5;

I recommend you try to learn assembler code, then you can make a very simple program, with a few local variables, and compile it to assembler code and read it to see exactly how it works.

There is often confusion between stack semantics vs stack region (or storage area). Same goes for heap. As well, the proliferation of "stack based virtual machines like JVM and CLR" mislead non-C and C++ programmers into thinking the native runtime stack works the same way.

It is important to differentiate:

  1. Semantics vs Region - One doesn't mean the other. The C and C++ stack is not the Java / CLR stack.
  2. "stack-based call frames" from just "call frames" - Call frames don't have to be stacked

Stacks on most architectures provide random access semantics of O(1) . The common example is the immediate and base+offset addressing modes and the stack and base pointers in x86. The actual stack area is allocated in a LIFO fashion, but the individual variables are random accessible, O(1) . If you wanted the stack to be gigantic, it could be.

Space is allocated like a LIFO stack. Variables are accessed within the stack like an array/vector or by an absolute address (pointer).

So, no, in C and C++, you aren't limited to a single variable at a time.

You have a little confusion about data organization and access . In stack memory is organized in such a way that new data can be added or removed only from the "top". This however has nothing to do with restrictions about accessing other elements. Such restrictions can be present in some logical stack implementations (like std::stack from C++ STL), but they are not mandatory.

Hardware stack is really more like a fixed size array, with variable array start location (stack pointer), so other elements can be accessed by indexing stack pointer. The difference from "standard" array is that it can contain elements of different size.

A stack frame consists of several elements, including:

- Return address

The address in the program where the function is to return upon completion

- Storage for local data

Memory allocated for local variables

- Storage for parameters

Memory allocated for the function's parameters

- Stack and base pointers

Pointers used by the runtime system to manage the stack

A stack pointer usually points to the top of the stack. A stack base pointer (frame pointer) is often present and points to an address within the stack frame, such as the return address. This pointer assists in accessing the stack frame's elements. Neither of these pointers are C pointers. They are addresses used by the runtime system to manage the program stack. If the runtime system is implemented in C, then these pointers may be real C pointers.

What you want to know is how stack frames work.

To use a stack frame you have to have several registers pointing to several "points of interest" on said stack frame and modify them or use an offset of where they are pointing. An example would be:

main() is about to call foo() . The base of main() is pointed to by the "base pointer" register EBP. Until now, main() has been using all the registers for its own stack frame. Now it will need to save the contents of those registers if it is to use them again after the call. After the call, foo() will (among other things) set up its own stack frame by allocating memory for its local variables, setting the "stack pointing" register called ESP to the top of its stack frame while saving the address of the main() base pointer and by copying the contents of the "next instruction" register called EIP so that it knows where to return after its completion. The stack frame of foo() is now on top of the stack frame of main() and the stack looks something like this:

[Registers that foo() saved.]

[Local variables of foo() .]

[ main() base pointer address. EBP points here and will point to the address stored here after foo() is done.]

[ main() return address ( foo() will return to where this address is pointing.)]

[Arguments for foo() .]

[Registers that main() saved.]

[...]

As you can see, we can access both the arguments of foo() as well as its local variables as simple offsets from where the EBP register points. If the first local variable is 4 bytes long we are going to find it at EBP - 4 for example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM