Order of local variable allocation on the stack
c, gcc, memory, stack, x86
Solution
I've no idea why GCC organizes its stack the way it does (though I guess you could crack open its source or this paper and find out), but I can tell you how to guarantee the order of specific stack variables if for some reason you need to. Simply put them in a struct:
void function1() {
struct {
int x;
int y;
int z;
int *ret;
} locals;
}
If my memory serves me correctly, spec guarantees that `&ret > &z > &y > &x`. I left my K&R at work so I can't quote chapter and verse though.
Problem
Take a look at these two functions: ``` void function1() { int x; int y; int z; int *ret; } void function2() { char buffer1[4]; char buffer2[4]; char buffer3[4]; int *ret; } ``` If I break at `function1()` in `gdb`, and print the addresses of the variables, I get this: ``` (gdb) p &x $1 = (int *) 0xbffff380 (gdb) p &y $2 = (int *) 0xbffff384 (gdb) p &z $3 = (int *) 0xbffff388 (gdb) p &ret $4 = (int **) 0xbffff38c ``` If I do the same thing at `function2()`, I get this: ``` (gdb) p &buffer1 $1 = (char (*)[4]) 0xbffff388 (gdb) p &buffer2 $2 = (char (*)[4]) 0xbffff384 (gdb) p &buffer3 $3 = (char (*)[4]) 0xbffff380 (gdb) p &ret $4 = (int **) 0xbffff38c ``` You'll notice that in both functions, `ret` is stored closest to the top of the stack. In `function1()`, it is followed by `z`, `y`, and finally `x`. In `function2()`, `ret` is followed by `buffer1`, then `buffer2` and `buffer3`. Why is the storage order changed? We're using the same amount of memory in both cases (4 byte `int`s vs 4 byte `char` arrays), so it can't be an issue of padding. What reasons could there be for this reordering, and furthermore, is it possible by looking at the C code to determine ahead of time how the local variables will be ordered? Now I'm aware that the ANSI spec for C says nothing about the order that local variables are stored in and that the compiler is allowed to chose its own order, but I would imagine that the compiler has rules as to how it takes care of this, and explanations as to why those rules were made to be as they are. For reference I'm using GCC 4.0.1 on Mac OS 10.5.7