Two hours ago I thought I had full understanding of how the stack works (at least how it's handled in C). But I've come to notice some unexpected (to me) behaviour in my programs.
We know the stack grows towards lower memory addresses (I'm talking about PCs, in my case: Intel 64 bits, Ubuntu). So when a new stack frame is created, the objects that belong to that frame have lower memory addresses that all the previous ones. What surprised me is this: the objects within a frame have higher memory addresses the later they where declared. This shocked me quite a bit because I thought variables that were declared earlier earned higher memory addresses.
Let me show what exactly what I mean with an example in C.
#include <stdio.h>
void foo()
{
int firstVar = 1;
int secondVar = 2;
printf("firstVar is at: %p\n", &firstVar);
printf("secondVar is at: %p\n", &secondVar);
}
int main(void)
{
int mainVar = 0;
printf("mainVar is at: %p\n", &mainVar);
foo();
return 0;
}
After compiling with gcc (-g, -ansi and -pedantic flags) the output is:
mainVar is at: 0x7ffd1ec0fadc
firstVar is at: 0x7ffd1ec0fab8
secondVar is at: 0x7ffd1ec0fabc
As expected, mainVar has a higher memory address than the ones in the foo() stack frame. However, firstVar has a lower memory address than secondVar even though is was declared before. Looking at the disassembling of foo() shows this behaviour:
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub $0x10,%rsp
0x0000000000400535 <+8>: movl $0x1,-0x8(%rbp)
0x000000000040053c <+15>: movl $0x2,-0x4(%rbp)
...
The 1 is put four bytes before the 2, showing once again that firstVar has a lower memory address than secondVar.
My question is: why is that? According to all the bibliography I've read, objects within the same stack frame should have higher memory addresses the earlier they where declared. And bibliography means internet (this site for example) and reputable books. I'm using a very standard system so I doubt any ELF or ABI weird stuff is going on...
Any ideas? Thanks for reading through.
cdeclcalling convention for details/examples. And remember that pascal and other languages have different conventionscdeclconventions (C calling conventions), that any compatable C/C++ compiler must implement: <msdn.microsoft.com/en-us/library/zkwh89ks.aspx> You might also want to look at thestdcallconventions used by the WINAPI <msdn.microsoft.com/en-us/library/zxk0tw93.aspx>