Does stack grow upward or downward?

83,990

Solution 1

The behavior of stack (growing up or growing down) depends on the application binary interface (ABI) and how the call stack (aka activation record) is organized.

Throughout its lifetime a program is bound to communicate with other programs like OS. ABI determines how a program can communicate with another program.

The stack for different architectures can grow the either way, but for an architecture it will be consistent. Please check this wiki link. But, the stack's growth is decided by the ABI of that architecture.

For example, if you take the MIPS ABI, the call stack is defined as below.

Let us consider that function 'fn1' calls 'fn2'. Now the stack frame as seen by 'fn2' is as follows:

direction of     |                                 |
  growth of      +---------------------------------+ 
   stack         | Parameters passed by fn1(caller)|
from higher addr.|                                 |
to lower addr.   | Direction of growth is opposite |
      |          |   to direction of stack growth  |
      |          +---------------------------------+ <-- SP on entry to fn2
      |          | Return address from fn2(callee) | 
      V          +---------------------------------+ 
                 | Callee saved registers being    | 
                 |   used in the callee function   | 
                 +---------------------------------+
                 | Local variables of fn2          |
                 |(Direction of growth of frame is |
                 | same as direction of growth of  |
                 |            stack)               |
                 +---------------------------------+ 
                 | Arguments to functions called   |
                 | by fn2                          |
                 +---------------------------------+ <- Current SP after stack 
                                                        frame is allocated

Now you can see the stack grows downward. So, if the variables are allocated to the local frame of the function, the variable's addresses actually grows downward. The compiler can decide on the order of variables for memory allocation. (In your case it can be either 'q' or 's' that is first allocated stack memory. But, generally the compiler does stack memory allocation as per the order of the declaration of the variables).

But in case of the arrays, the allocation has only single pointer and the memory needs to be allocated will be actually pointed by a single pointer. The memory needs to be contiguous for an array. So, though stack grows downward, for arrays the stack grows up.

Solution 2

This is actually two questions. One is about which way the stack grows when one function calls another (when a new frame is allocated), and the other is about how variables are laid out in a particular function's frame.

Neither is specified by the C standard, but the answers are a little different:

  • Which way does the stack grow when a new frame is allocated -- if function f() calls function g(), will f's frame pointer be greater or less than g's frame pointer? This can go either way -- it depends on the particular compiler and architecture (look up "calling convention"), but it is always consistent within a given platform (with a few bizarre exceptions, see the comments). Downwards is more common; it's the case in x86, PowerPC, MIPS, SPARC, EE, and the Cell SPUs.
  • How are a function's local variables laid out inside its stack frame? This is unspecified and completely unpredictable; the compiler is free to arrange its local variables however it likes to get the most efficient result.

Solution 3

The direction is which stacks grow is architecture specific. That said, my understanding is that only a very few hardware architectures have stacks that grow up.

The direction that a stack grows is independent of the the layout of an individual object. So while the stack may grown down, arrays will not (i.e &array[n] will always be < &array[n+1]);

Solution 4

There's nothing in the standard that mandates how things are organized on the stack at all. In fact, you could build a conforming compiler that didn't store array elements at contiguous elements on the stack at all, provided it had the smarts to still do array element arithmetic properly (so that it knew, for example, that a1 was 1K away from a[0] and could adjust for that).

The reason you may be getting different results is because, while the stack may grow down to add "objects" to it, the array is a single "object" and it may have ascending array elements in the opposite order. But it's not safe to rely on that behaviour since direction can change and variables could be swapped around for a variety of reasons including, but not limited to:

  • optimization.
  • alignment.
  • the whims of the person the stack management part of the compiler.

See here for my excellent treatise on stack direction :-)

In answer to your specific questions:

  1. Does stack grow up or down?
    It doesn't matter at all (in terms of the standard) but, since you asked, it can grow up or down in memory, depending on the implementation.
  2. What happen between a[2] and q memory addresses? Why there are a big memory difference there? (20 bytes)?
    It doesn't matter at all (in terms of the standard). See above for possible reasons.

Solution 5

On an x86, the memory "allocation" of a stack frame consists simply of subtracting the necessary number of bytes from the stack pointer (I believe other architectures are similar). In this sense, I guess the stack growns "down", in that the addresses get progressively smaller as you call more deeply into the stack (but I always envision the memory as starting with 0 in the top left and getting larger addresses as you move to the right and wrap down, so in my mental image the stack grows up...). The order of the variables being declared may not have any bearing on their addresses -- I believe the standard allows for the compiler to reorder them, as long as it doesn't cause side effects (someone please correct me if I'm wrong). They're just stuck somewhere into that gap in the used addresses created when it subtracts the number of bytes from the stack pointer.

The gap around the array may be some kind of padding, but it's mysterious to me.

Share:
83,990
Admin
Author by

Admin

Updated on October 17, 2020

Comments

  • Admin
    Admin over 3 years

    I have this piece of code in c:

    int q = 10;
    int s = 5;
    int a[3];
    
    printf("Address of a: %d\n",    (int)a);
    printf("Address of a[1]: %d\n", (int)&a[1]);
    printf("Address of a[2]: %d\n", (int)&a[2]);
    printf("Address of q: %d\n",    (int)&q);
    printf("Address of s: %d\n",    (int)&s);
    

    The output is:

    Address of a: 2293584
    Address of a[1]: 2293588
    Address of a[2]: 2293592
    Address of q: 2293612
    Address of s: 2293608
    

    So, I see that from a to a[2], memory addresses increases by 4 bytes each. But from q to s, memory addresses decrease by 4 byte.

    I wonder 2 things:

    1. Does stack grow up or down? (It looks like both to me in this case)
    2. What happen between a[2] and q memory addresses? Why there are a big memory difference there? (20 bytes).

    Note: This is not homework question. I am curious on how stack works. Thanks for any help.