1

Running the following program on gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 and Intel(R) Core(TM)2 Duo CPU, I want to verify the c program stack grows downward, I write following code:

    #include <stdio.h>
    #include <malloc.h>
    #include <string.h>

    static int a = 1;
    static int b;
    int c = 2;
    int d;

    void foo(void)
    {
        int *p1;
        int *p2;
        int *p3;
        int *p4;

        printf("&p1\t%p\n", &p1);
        printf("&p2\t%p\n", &p2);
        printf("&p3\t%p\n", &p3);
        printf("&p4\t%p\n", &p4);
    }

    int main()
    {
        static int e = 3;
        static int f;
        int g = 4;
        int h;

        char *str1 = "abc";
        char *str2 = "abc";
        char *str3;
        char *str4;

        printf("&\"abc\"\t%p\n", &"abc");
        printf("&str1\t%p\n", &str1);
        printf("&str2\t%p\n", &str2);
        printf("str1\t%p\n", str1);
        printf("str2\t%p\n", str2);

        printf("&str3\t%p\n", &str3);
        printf("str3\t%p\n", str3);

        str4 = (char *)malloc(strlen("abc")*sizeof(char));
        printf("&str4\t%p\n", &str4);
        printf("str4\t%p\n", str4);

        printf("&g\t%p\n", &g);
        printf("&h\t%p\n", &h);

        foo();

        return 0;
    }

I get this result:

    &"abc"  0x8048680
    &str1   0xbff1be20
    &str2   0xbff1be24
    str1    0x8048680
    str2    0x8048680
    &str3   0xbff1be28
    str3    0x8048599
    &str4   0xbff1be2c
    str4    0x950f008
    &g  0xbff1be18
    &h  0xbff1be1c
    &p1 0xbff1bde0
    &p2 0xbff1bde4
    &p3 0xbff1bde8
    &p4 0xbff1bdec

I find the addresses of str1, str2, str3, str4 grows upward, the addresses of p1, p2, p3, p4 grows upward too, not downward, why?

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
Victor S
  • 4,021
  • 15
  • 43
  • 54

4 Answers4

5

The C standard doesn't say anything about a stack, much less which direction it grows in.

Any behaviour you observe is entirely down to your particular compiler (which in turn will be influenced by the particular platform you're running on.)

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
3

You program does not test the direction of the stack.

    int *p1;
    int *p2;
    int *p3;
    int *p4;

The compiler can push the automatic objects in the reverse order they appear in the program.

A good check to test the direction of the stack (which really goes upward on some platforms), is to check the addresses of automatic objects in two different functions, one function calling the other function.

void f(void)
{
    int a = 0;
    g(&a);
}

void g(int *p)
{
    int a = 0;

    if (p - &a > 0) printf("stack goes upward\n");
    else  printf("stack goes downard\n");
}
ouah
  • 142,963
  • 15
  • 272
  • 331
2

Actually, it does grow downward on your platform which I guess is Linux + 32 bit x86. There are 2 registers used for addressing the stack on the x86 platform, Base Pointer (BP) and Stack Pointer (SP). SP is incremented automatically as values are pushed, and decremented as they are popped. Before a function is called, the callee pushes the function on stack, in reverse order, the first argument being the topmost one on the stack.

However, in the function body, the compiler emits code that stores the original SP in BP, then increments the SP enough to cover for all local variables; these are generally allocated in increasing direction, and addressed through the BP pointer within the function body. Notably, the local variables in your case are not "pushed" on the stack as they are uninitialized.

0

Obviously local variables in main are located at higher addresses in stack than those in foo, so your stack grows downwards - no need to worry :)

To support the case for compiler dependent variable placement, consider the result when running your code on Mac OS X with GCC-LLVM 4.2.1:

&p1     0x7fff63a5dbf8  ^
&p2     0x7fff63a5dbf0  |
&p3     0x7fff63a5dbe8  |
&p4     0x7fff63a5dbe0  |

On Linux with GCC 4.2.4-1ubuntu4:

&p1     0x7fffa1e6d7b8  ^
&p2     0x7fffa1e6d7b0  |
&p3     0x7fffa1e6d7a8  |
&p4     0x7fffa1e6d7a0  |

Same behaviour observed with GCC 4.4.3-4ubuntu5.1. But with Intel C Compiler v11.0 things get reversed:

&p1     0x7fff59a84c20  |
&p2     0x7fff59a84c28  |
&p3     0x7fff59a84c30  |
&p4     0x7fff59a84c38  v

The difference is clearly visible in the assembly code produced by both compilers. GCC uses base pointer (EBP/RBP) based addressing with negative offsets (i.e. addressing relative to the top of the stack frame) while ICC uses stack pointer (ESP/RSP) based addressing with positive offsets (i.e. addressing relative to the bottom of the stack frame). In both cases p1 has the lowest absolute offset, p2 has the next lowest absolute offset and so on.

GCC can also use stack pointer based addressing if supplied the -fomit-frame-pointer option (automatically turned on with higher optimisation levels), but at least GCC up to 4.4.3 still retains the old variable layout, i.e. p1 now has the highest offset, p2 has the next highest offset and so on. Probably that has changed in newer GCC versions.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186