Hello, It's nice to see a more security-minded release of gcc with v4. Variables are moved around to reduce chances for exploitation, -fstack-protector, etc. Great!
Why are local variables once-again adjacent to the saved frame pointer though? gcc v 2 called and wants one of its "features" back. func(char *b){ char buf[512]; if( strlen(b) > sizeof buf) return; strcpy(buf, b); } 0x080483a7 <func+3>: sub $0x208,%esp 0x080483ad <func+9>: mov 0x8(%ebp),%eax 0x080483b0 <func+12>: mov %eax,0x4(%esp) 0x080483b4 <func+16>: lea 0xfffffe00(%ebp),%eax 0x080483ba <func+22>: mov %eax,(%esp) 0x080483bd <func+25>: call 0x80482e8 <[EMAIL PROTECTED]> 0x080483c2 <func+30>: leave 0x080483c3 <func+31>: ret 0x208 = 520 bytes; alright padding can be useful 0xfffffe00(%ebp) = -512 + ebp. OOPS! In effect the padding is no longer in between the saved frame pointer and the local vars. I've seen this in various versions of gcc 4. Gcc 3 would have placed this padding between the saved frame pointer and the local vars. Here's the result from gcc 3.4: 0x08048367 <func+3>: sub $0x218,%esp ... 0x08048374 <func+16>: lea 0xfffffdf8(%ebp),%eax Thats -520+ebp. It also takes a little bit more padding. Any good reason NOT to pad between the local vars and control data? P.S. check out this cute rendition from gcc 4.1.1: #include <stdio.h> #include <string.h> int main(int argc, char *argv[]){ char buf[512]; if(strlen(argv[1]) <= sizeof buf) strcpy(buf, argv[1]); } Dump of assembler code for function main: 0x080483a4 <main+0>: lea 0x4(%esp),%ecx 0x080483a8 <main+4>: and $0xfffffff0,%esp 0x080483ab <main+7>: pushl 0xfffffffc(%ecx) 0x080483ae <main+10>: push %ebp 0x080483af <main+11>: mov %esp,%ebp 0x080483b1 <main+13>: push %edi 0x080483b2 <main+14>: push %ecx 0x080483b3 <main+15>: sub $0x210,%esp 0x080483b9 <main+21>: mov %ecx,0xfffffdf4(%ebp) 0x080483bf <main+27>: mov 0xfffffdf4(%ebp),%edx 0x080483c5 <main+33>: mov 0x4(%edx),%eax 0x080483c8 <main+36>: add $0x4,%eax 0x080483cb <main+39>: mov (%eax),%eax 0x080483cd <main+41>: mov $0xffffffff,%ecx 0x080483d2 <main+46>: mov %eax,0xfffffdf0(%ebp) 0x080483d8 <main+52>: mov $0x0,%al 0x080483da <main+54>: cld 0x080483db <main+55>: mov 0xfffffdf0(%ebp),%edi 0x080483e1 <main+61>: repnz scas %es:(%edi),%al 0x080483e3 <main+63>: mov %ecx,%eax 0x080483e5 <main+65>: not %eax 0x080483e7 <main+67>: dec %eax 0x080483e8 <main+68>: cmp $0x200,%eax 0x080483ed <main+73>: ja 0x804840f <main+107> 0x080483ef <main+75>: mov 0xfffffdf4(%ebp),%edx 0x080483f5 <main+81>: mov 0x4(%edx),%eax 0x080483f8 <main+84>: add $0x4,%eax 0x080483fb <main+87>: mov (%eax),%eax 0x080483fd <main+89>: mov %eax,0x4(%esp) 0x08048401 <main+93>: lea 0xfffffdf8(%ebp),%eax 0x08048407 <main+99>: mov %eax,(%esp) 0x0804840a <main+102>: call 0x80482e8 <[EMAIL PROTECTED]> 0x0804840f <main+107>: add $0x210,%esp 0x08048415 <main+113>: pop %ecx <----immediate control 0x08048416 <main+114>: pop %edi | 0x08048417 <main+115>: pop %ebp V 0x08048418 <main+116>: lea 0xfffffffc(%ecx),%esp 0x0804841b <main+119>: ret 0x0804841c <main+120>: nop esp can be controlled controlled right away before the "ret" instruction. This new prologue/epilogue opened up a fun new possibility for an off-by-one in main(). One final question, what is the purpose of this new prologue and epilogue for main? Why re-align the stack and push the saved ret to a new place [pushl 0xfffffffc(%ecx)] if you're going to just use the old one anyway [ lea 0xfffffffc(%ecx),%esp] ??? have phuN!