I have some c code that I compile with gcc in cygwin and the stack for the function call grows by more than I expect it to. I don't know why since the local variables within the function should take 24 bytes max...
Here's the code:
main() { function(1,2,3);
}
void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; ...
}
It gives me the following assembly output:
(gdb) disassemble function Dump of assembler code for function function: 0x00401050 <function+0>: push %ebp 0x00401051 <function+1>: mov %esp,%ebp 0x00401053 <function+3>: sub $0x28,%esp
Why does the stack increase by 40? I expect to increase by 24 bytes.
bartab4u <spamt...@crayne.org> writes: > void function(int a, int b, int c) { > char buffer1[5]; > char buffer2[10]; > ... > }
> Why does the stack increase by 40? I expect to increase by 24 bytes.
Since you didn't show the rest of your function, how can we tell? It might be used for temporaries, outgoing arguments, alloca(), or who knows what else.
On Dec 11, 4:53 pm, DJ Delorie <d...@delorie.com> wrote:
> bartab4u <spamt...@crayne.org> writes: > > void function(int a, int b, int c) { > > char buffer1[5]; > > char buffer2[10]; > > ... > > }
> > Why does the stack increase by 40? I expect to increase by 24 bytes.
> Since you didn't show the rest of your function, how can we tell? It > might be used for temporaries, outgoing arguments, alloca(), or who > knows what else.
void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; }
(gdb) disassemble function Dump of assembler code for function function: 0x00401050 <function+0>: push %ebp 0x00401051 <function+1>: mov %esp,%ebp 0x00401053 <function+3>: sub $0x28,%esp 0x00401056 <function+6>: leave 0x00401057 <function+7>: ret End of assembler dump.
>I have some c code that I compile with gcc in cygwin and the stack for >the function call grows by more than I expect it to. I don't know why >since the local variables within the function should take 24 bytes >max... >... >Why does the stack increase by 40? I expect to increase by 24 bytes.
This question has been asked many times in the past couple of years, and to my knowledge the only answer has been "because it does". gcc tries to maintain some kind of alignment in the stack (16? 32?), which accounts of some of the difference, but that doesn't explain everything. -- Tim Roberts, t...@probo.com Providenza & Boekelheide, Inc.
> >I have some c code that I compile with gcc in cygwin and the stack for > >the function call grows by more than I expect it to. I don't know why > >since the local variables within the function should take 24 bytes > >max... > >... > >Why does the stack increase by 40? I expect to increase by 24 bytes.
> This question has been asked many times in the past couple of years, and to > my knowledge the only answer has been "because it does". gcc tries to > maintain some kind of alignment in the stack (16? 32?), which accounts of > some of the difference, but that doesn't explain everything.
So I wrote a quick script that assembles (gcc -S) a function as follows:
void function() { char buffer[X];
}
for each X = 0, 1, 2 .. 100
Then I partitioned the 100 assembled functions by equality.
I did see some kind of stack padding. As you can see for a buffer size of 13 through 28 (which includes the 5+10=15 char buffer from the original question), the stack grows 40 in these cases. It seems it does not have anything to do with the functions parameters.
>From the below results can anyone spot a pattern between the buffer
size versus the stack size?
Also, I noticed that when the buffer size is 8 or above the following is inserted into the function:
Anyone know what this does? What does "$gs:20" mean and what is it doing in this case? And what are those xors about?
I have included a summary, the output of the script and the script itself below.
Regards, Andrew.
SUMMARY
For a buffer size of 0 the stack size is 0 For a buffer size of 1 to 7 the stack size is 16 For a buffer size of 8 to 12 the stack size is 24 For a buffer size of 13 to 28 the stack size is 40 For a buffer size of 29 to 44 the stack size is 56 For a buffer size of 45 to 60 the stack size is 72 For a buffer size of 61 to 76 the stack size is 88 For a buffer size of 77 to 92 the stack size is 104 For a buffer size of 93 to 100 the stack size is 120
GENF.OUT
For a buffer size of: 0 gcc output:
pushl %ebp movl %esp, %ebp popl %ebp ret
For a buffer size of: 1, 2, 3, 4, 5, 6, 7 gcc output:
pushl %ebp movl %esp, %ebp subl $16, %esp leave ret
For a buffer size of: 8, 9, 10, 11, 12 gcc output:
> movl %gs:20, %eax > movl %eax, -4(%ebp) > xorl %eax, %eax > movl -4(%ebp), %eax > xorl %gs:20, %eax > je .L3 > call __stack_chk_fail > .L3: > Anyone know what this does? What does "$gs:20" mean and what is it > doing in this case? And what are those xors about?
On further reflection I've figured this part out at least:
It looks like when the stack size is > 8 gcc puts in a stack corruption check. It pushes the value at %gs:20 onto the stack, and then once the function is complete it checks to see that it is still intact....
> > movl %gs:20, %eax > > movl %eax, -4(%ebp) > > xorl %eax, %eax > > movl -4(%ebp), %eax > > xorl %gs:20, %eax > > je .L3 > > call __stack_chk_fail > > .L3: > > Anyone know what this does? What does "$gs:20" mean and what is it > > doing in this case? And what are those xors about?
> On further reflection I've figured this part out at least:
> It looks like when the stack size is > 8 gcc puts in a stack > corruption check. It pushes the value at %gs:20 onto the stack, and > then once the function is complete it checks to see that it is still > intact....
> ...Retrieve bottom of stack and compare with gs:20 again. If not > equal, the stack frame must have become corrupted, so call > __stack_chk_fail.
> This check increases the stack frame size by 4. It still doesn't > explain the rest of the padding.
At first glance it appears that GCC is simply trying to keep 16 byte alignment on the stack so long as there are more than 7 bytes of locals. Remember that the stack has not only the stack frame, it has the old epb value and the return address, so there's an extra 8 bytes right there that you have to deal with for alignment purposes, plus the stack check word.
For routines with smaller amounts of locals, it looks like he's just forcing 8 byte alignment, which is odd, unless he's only allowing small leaf functions (those that don't call anything, so that continuing alignment doesn't matter) to have alignment less than 16 bytes (which is quite plausible). I'd test it, but I'm away from any useful copy of GCC at the moment.
On Dec 16, 7:20 am, "robertwess...@yahoo.com" <spamt...@crayne.org> wrote:
> At first glance it appears that GCC is simply trying to keep 16 byte > alignment on the stack so long as there are more than 7 bytes of > locals. Remember that the stack has not only the stack frame, it has > the old epb value and the return address, so there's an extra 8 bytes > right there that you have to deal with for alignment purposes, plus > the stack check word. >From Tim Prince on the gcc list I learned that the reason that GCC
keeps the stack aligned to 16 bytes (by default) is that it is required by the Streaming SIMD Extensions (SSE). <http:// en.wikipedia.org/wiki/Streaming_SIMD_Extensions>
However, I am still not convinced that what we are seeing is 16-byte alignment.