This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

What happens on the stack when calling a function? (gcc-3.4.3)


Hi folks!

I stumbled across some strange stuff on the stack when calling a
function with gcc-3.4.3.

I wanted to learn something about the stack and buffer overflows. So I
wrote this little piece of c code (s1.c):

#include <string.h>
void f( char *args) {
   char buf1[10];
   char buf2[4] = "ABC";
   strcpy (buf1, args);
}

int main (int argc, char *argv[]) {
   if (argc > 1) {
      printf("Input: %s\n", argv[1]);
      f(argv[1]);
   }
   return 0;
}

Compiled it and fired up gdb:

$ gcc -g -o s1 s1.c
$ gdb s1
[...]
(gdb) list
1       #include <string.h>
2       void f( char *args) {
3               char buf1[10];
4               char buf2[4] = "ABC";
5               strcpy (buf1, args);
6       }
7
8       int main (int argc, char *argv[]) {
9               if (argc > 1) {
10                      printf("Input: %s\n", argv[1]);
(gdb) break 6
Breakpoint 1 at 0x80483e4: file s1.c, line 6.
(gdb) run `python -c 'print "A"*10'`
Starting program: /mnt/data/studium/vi/rlp/bo/s1 `python -c 'print "A"*10'`
Input: AAAAAAAAAA

Breakpoint 1, f (args=0xbffff3c3 "AAAAAAAAAA") at s1.c:6
6       }
(gdb)

Note: I know that 10 A's is to long (10 A's + \0), but this is not the
problem here.
In fact, the program should throw a segmentation fault if it gets more
than 11 A's (and it does that on a debian box with gcc-2.95.4). But on
my system, it works with up to 23 A's.

AFAIK, when a funktion is called, the calling function pushes the
parameters and the adress of the next command after the function call
(Return Instruction Pointer, RIP) on the stack.
The function that is called saves the frame pointer (FP) on the stack
and then reserves space on the stack for local variables by decrementing
the stack pointer.
As the stack grows from top to bottom, at the breakpoint the stack
should look this:
RIP
FP
buf1
[..]
buf1
buf2
buf2
buf2

But in fact, it looks like this:

(gdb) info frame 0
Stack frame at 0xbffff170:
 eip = 0x80483e4 in f (s1.c:6); saved eip 0x8048430
 called by frame at 0xbffff190
 source language c.
 Arglist at 0xbffff168, args: args=0xbffff3c3 "AAAAAAAAAA"
 Locals at 0xbffff168, Previous frame's sp is 0xbffff170
 Saved registers:
  ebp at 0xbffff168, eip at 0xbffff16c
(gdb) x/12x buf2
0xbffff14c:     0x00434241      0x41414141      0x41414141      0xb7004141
0xbffff15c:     0xb7fd45e0      0x08048558      0xbffff178      0xbffff188
0xbffff16c:     0x08048430      0xbffff3c3      0xbffff3c3      0x00000000
(gdb)

As you can see buf2 is on the lowest adress, followed by buf1.
But what happend to the saved ebp (at 0xbffff168, value 0xbffff188) and
saved eip (at 0xbffff16c, value 0x8048430)?
Why are they not located at 0xbffff15c and 0xbffff160? Why is there an 8
byte "hole"? What is stored there?

Having a look at the assembler code:
(gdb) disass
Dump of assembler code for function f:
0x080483a4 <f+0>:       push   %ebp
0x080483a5 <f+1>:       mov    %esp,%ebp
0x080483a7 <f+3>:       sub    $0x38,%esp
0x080483aa <f+6>:       mov    0x8048538,%eax
0x080483af <f+11>:      mov    %eax,0xffffffe4(%ebp)
0x080483b2 <f+14>:      mov    0x8(%ebp),%eax
0x080483b5 <f+17>:      mov    %eax,0x4(%esp)
0x080483b9 <f+21>:      lea    0xffffffe8(%ebp),%eax
0x080483bc <f+24>:      mov    %eax,(%esp)
0x080483bf <f+27>:      call   0x80482dc <_init+72>
0x080483c4 <f+32>:      leave
0x080483c5 <f+33>:      ret

I've tested this on a gcc-2.95.4 on a Debian system and everything was
at the expected location in memory.
Assembler looks like this:

(gdb) disass
Dump of assembler code for function f:
0x8048430 <f>:  push   %ebp
0x8048431 <f+1>:        mov    %esp,%ebp
0x8048433 <f+3>:        sub    $0x18,%esp
0x8048436 <f+6>:        mov    0x80484f4,%eax
0x804843b <f+11>:       mov    %eax,0xfffffff0(%ebp)
0x804843e <f+14>:       add    $0xfffffff8,%esp
0x8048441 <f+17>:       mov    0x8(%ebp),%eax
0x8048444 <f+20>:       push   %eax
0x8048445 <f+21>:       lea    0xfffffff4(%ebp),%eax
0x8048448 <f+24>:       push   %eax
0x8048449 <f+25>:       call   0x8048338 <strcpy>
0x804844e <f+30>:       add    $0x10,%esp
0x8048451 <f+33>:       leave
0x8048452 <f+34>:       ret
End of assembler dump.

Line <f+3> seems to be the key: gcc-3.4.3 just "wastes" some space.
But why?
It may be an alignment thing for cache optimization, but it doesn't go
away with -O0...

Here are some specs about my system:

$ uname -a
Linux d6k 2.6.11-gentoo-r6 #8 SMP Wed May 11 02:12:58 CEST 2005 i686
Intel(R) Pentium(R) M processor 1.86GHz GenuineIntel GNU/Linux
$ gcc -v
Lese Spezifikationen von /usr/lib/gcc/i686-pc-linux-gnu/3.4.3-20050110/specs
Konfiguriert mit:
/var/tmp/portage/gcc-3.4.3.20050110-r2/work/gcc-3.4.3/configure
--enable-version-specific-runtime-libs --prefix=/usr
--bindir=/usr/i686-pc-linux-gnu/gcc-bin/3.4.3-20050110
--includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.3-20050110/include
--datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.3-20050110
--mandir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.3-20050110/man
--infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.3-20050110/info
--with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.3-20050110/include/g++-v3
--host=i686-pc-linux-gnu --disable-altivec --enable-nls
--without-included-gettext --with-system-zlib --disable-checking
--disable-werror --disable-libunwind-exceptions --disable-multilib
--disable-libgcj --enable-languages=c,c++,f77 --enable-shared
--enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu
Thread-Modell: posix
gcc-Version 3.4.3-20050110 (Gentoo 3.4.3.20050110-r2,
ssp-3.4.3.20050110-0, pie-8.7.7)

I've tried gcc with -no-pie and -no-stack-protector-all -march=i386 and
also gcc-3.3.5, but got the same behaviour.

I don't know if this behaviour is caused by some Gentoo-specific
configuration or by gcc >3, unfortunately, I've no access to another
system to do more testing.
I would be really thankful if someone could explain me this behaviour.

Greets,
Daniel Hepper


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]