2

I just want to get a better understanding of what a stack is in the address space (i.e you have code/text, heap, data, and a stack)

basically my understanding is that a stack contains local variables, but then what is the difference between what the data contains and what a stack contains? isn't data variables as well?

If a program has a recursive call to a function a() does it mean that for every level of recursion there is a new stack?

jgauffin
  • 95,399
  • 41
  • 227
  • 352
Saad
  • 19,836
  • 13
  • 41
  • 68
  • 1
    Stacks are not really specific to DRAM. They are a data structure. It is implemented by processors to ease function calls and recursion. I have posted some details below. – Aater Suleman May 19 '11 at 03:14

3 Answers3

5

A stack is usually different to data only in the way it's used and managed. While non-local variables themselves usually have a known specific memory location, things on the stack are found relative to a register (stack pointer or base pointer or some such).

A stack usually contains local variables, passed parameters and control information for managing the stack itself.

And, if you make a recursive call, you don't get a new stack, just a new stack frame. A frame is a chunk of the stack relevant to the current stack depth (whether that's by recursion or just regular function calls). That's what makes recursion possible, the fact that the variables for a given depth are independent of those for other depths.

Keep in mind that this is all dependent, of course, on the architecture. My description above is a common case but there are architectures where stacks are done differently, such as SPARC, the System z and RCA1802.

More details can be found here (how frames work) and here (weird stacks).

Community
  • 1
  • 1
paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
1

First, a small clarification. Stacks are not necessarily in DRAM. they are just a structure that can be formed in any memory: DRAM, caches, disk.

To understand a stack, you should first understand what is a stack. It is like a stack of trays, the properties that make it a stack are:

  • You can only access the top element of the stack
  • It is Last In First Out, i.e., when you go to get a data from a stack you get the data that was stored last on the stack.

The act of storing something in a stack is called PUSH and removing it is called a POP. Say I do the following to an empty stack:

PUSH A
PUSH B
PUSH C

Then the stack will contain

C - Top
B
A

Now if I execute a POP (notice there is no operand here), it will return C and the stack will contain

B -- top of stack
A

So stack in processors is just a hardware implementation of the above algorithm.

A register contains the address of the top of stack called stack point The ISA (Instruction Set Architecture) provides PUSH and POP instructions to access the stack variables as I showed above.

This is a very useful construct. A stack is used to store local variables, basically temporary data that you want to remove at the end of a function call. It specifically helps with function calls. When a function is called, the variables of the newly called function's local variables are pushed on the stack.

foo(){
    int a;   
    int b;    // both registers containing a and b are PUSHed here on the stack 
    c = bar(); // pop the stack to get value of c 
    print c
}

bar(){
   int z; // local variables pushed on top of the stack
   z = ... 
   return z; // pop all local variables of bar(), then push z on the stack 
}

I hope the above helps.

Luqmaan
  • 2,012
  • 26
  • 34
Aater Suleman
  • 2,110
  • 15
  • 10
  • From my recollection, this answer is wrong in a number of the specific details, though essentially correct in concept. In particular, returning variables is not typically (ever?) done using the stack, but rather by loading a specific register with the return value, according to whatever calling-conventions are being employed. – Lawrence Dol May 19 '11 at 03:32
  • Interesting point. There is no reason to not the use stack for return value. Whether or not to use the stack is actually a property of the compiler and has nothing do with semantics of a stack or the working of the program. In fact, Motorola's compiler for HC12 used the stack. Using a register is an optimization to save a redundant push and pop. It is sometimes ok to use the stack if not enough registers are available. Gcc does that at times (rarely) and this also explain why the 6812 used stack because there were very few registers. Just curious, what other ways did you find my answer wrong? – Aater Suleman May 20 '11 at 00:53
  • if `int z` pushes z onto the stack, and `return z` also pushes z onto the stack, then the machine code will have trouble reseting the `SP` after returning without destroying the return value; the code before the `RET` instruction certainly can't do it, but the invoking code would need too much knowledge about the invoked subroutine (unless it stores the original value of `SP` in a register, I suppose). – Lawrence Dol May 20 '11 at 02:28
0

The following program should help you understand what is going on. You will see pointer examples of text, bss, heap, and stack. Text is usually executable code, bss are static/global variables, heap is dynamically allocated memory, stack contains local variables.

#include <stdlib.h>
#include <stdio.h>

#define TESTS 10
int numfeed = 0;
int numdead = 0;

recurse(int x)
{
  u_int pattern=0xfeedface;
  u_int *otherpattern = malloc(4);
  *otherpattern = 0xdeadbeef;

  printf("Feedface %d is at %p\n",x,&pattern);
  printf("deadbeef %d is at %p\n",x,otherpattern);

  if (--x == 0)
  {
    int *off;

    for(off = &pattern;numfeed<TESTS;off++)
    {
      if (*off == 0xfeedface)
        printf("Found feedface #%d at %p\n", ++numfeed, off);
      if (*off == 0xdeadbeef)
        printf("Found deadbeef #%d at %p -- WHAT?!?!!?!?\n", ++numdead, off);
    }
  }
  else
  {
    recurse(x);
  }
  // Not freeing otherpattern intentionally.
}


main()
{
  u_int *otherpattern = malloc(4);
  *otherpattern = 0xdeadbeef;
  int *off;

  recurse(TESTS);

  for(off = otherpattern+1;numdead<TESTS;off++)
  {
    if (*off == 0xfeedface)
      printf("Found feedface #%d at %p -- WHAT?!?!!!?!?\n", ++numfeed, off);
    if (*off == 0xdeadbeef)
      printf("Found deadbeef #%d at %p\n", 1+TESTS-(++numdead), off);
  }

  printf("numfeed is at %p\n",&numfeed);
  printf("recurse is at %p\n",&recurse);
}
Seth Robertson
  • 27,856
  • 5
  • 55
  • 52