4

I wrote a simple program in C, compiled it, opened it in gdb, set a breakpoint at line 11 and inspected the stack.

  1 #include<stdio.h>
  2
  3 int main(int argc, char *argv[]){
  4     char arr[4] = "AABB";
  5     int square = foo(2);
  6     exit(0);
  7 }
  8
  9 int foo(int x){
 10     char buff[4] = "CCDD";
 11     printf("Enter a value:"); // set breakpoint for this line
 12     gets(buff);
 13     return x*x;
 14 }
 15
 16 void bar(){
 17     printf("This program was hacked");
 18 }
 19

When I looked at the stack I found that after the main function is initialised but before foo(x) was called it placed 2 addresses for __libc_csu_init on the stack. I understand that every program calls init and fini, but shouldn't those references be placed on the stack before the main function is called?

(gdb) x/16a $esp
0xbffff110:    0x8000    0x44444343    0xbffff148    0x8048442 <main+48>
0xbffff120:    0x2    0xb7fbe000    0x804a000    0x80484c1 <__libc_csu_init+33>
0xbffff130:    0xb7fbe3bc    0x8048218    0x80484a9 <__libc_csu_init+9>    0x0
0xbffff140:    0x1    0x42424141    0x0    0xb7e0c5a6

Why is 0x42424141 at a higher address than __libc_csu_init?

Hugh Pearse
  • 141
  • 1
  • 4

2 Answers2

6

Your main function contains pointer to __libc_csu_init just before its return pointer, because that's how stack frame works; before entering a function, caller pushes a stack frame pointer and a return pointer.

Return pointer contains an address, to which function will return on function finish.

Frame pointer contains the address of the previous top of the stack, so it would know to where it should rewind the stack.

Unlike return pointer, stack frame pointer doesn't neccesarily need to be pushed on stack (its address can be stored in registers), but can be helpful for optimization, since accessing some address from current stack would be a matter of substracting from its value.

On the image below, that is example function call stack, stack frame pointer would be pushed where the "Frame pointer" arrow points - author assumed, that it would be stored in register only. If it was your program, it would contain address to __libc_csu_init.

enter image description here

For more information on frame pointers reffer to the Wikipedia article: https://en.wikipedia.org/wiki/Call_stack

And now, for a proof, let's compile a simple program with -fomit-frame-pointer flag (forces behaviour as in the image above), and without (pushes the frame pointer on the stack, like in your program):

int main(int argc, char *argv[])
{
// placing nop instruction just for readibility of disassembled code
asm("nop");
}

Compiled with no-pie, so PIC would not prevent me from breakpointing:

g++ answer.cpp -o answer -fno-pie -fomit-frame-pointer

Disassembled in gdb, breakpointed on the line with 'nop' instruction and printed first 12 words after stack pointer:

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004b2 <+0>: mov    %edi,-0x4(%rsp)
   0x00000000004004b6 <+4>: mov    %rsi,-0x10(%rsp)
   0x00000000004004bb <+9>: nop
   0x00000000004004bc <+10>:    mov    $0x0,%eax
   0x00000000004004c1 <+15>:    retq   
End of assembler dump.
(gdb) break *0x00000000004004bb
Breakpoint 1 at 0x4004bb
(gdb) r
Starting program: /home/xdbeef/answer 

Breakpoint 1, 0x00000000004004bb in main ()
(gdb) info registers ebp esp
ebp            0x4004d0            4195536
esp            0xffffdae8          -9496
(gdb) x/12xw 0x7fffffffdae8
0x7fffffffdae8: 0xf7a2d830  0x00007fff  0x00000000  0x00000000
0x7fffffffdaf8: 0xffffdbc8  0x00007fff  0xf7ffcca0  0x00000001
0x7fffffffdb08: 0x004004b2  0x00000000  0x00000000  0x00000000
(gdb) x/12xa 0x7fffffffdae8
0x7fffffffdae8: 0x7ffff7a2d830 <__libc_start_main+240>  0x0
0x7fffffffdaf8: 0x7fffffffdbc8  0x1f7ffcca0
0x7fffffffdb08: 0x4004b2 <main> 0x0
0x7fffffffdb18: 0x161e93edeaec9201  0x4003e0 <_start>
0x7fffffffdb28: 0x7fffffffdbc0  0x0
0x7fffffffdb38: 0x0 0xe9e16c9256ac9201
(gdb) 

As you see, the first and only address on main's stack frame was the return pointer.

And now with frame pointer:

g++ answer.cpp -o answer -fno-pie
(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004b2 <+0>: push   %rbp
   0x00000000004004b3 <+1>: mov    %rsp,%rbp
   0x00000000004004b6 <+4>: mov    %edi,-0x4(%rbp)
   0x00000000004004b9 <+7>: mov    %rsi,-0x10(%rbp)
   0x00000000004004bd <+11>:    nop
   0x00000000004004be <+12>:    mov    $0x0,%eax
   0x00000000004004c3 <+17>:    pop    %rbp
   0x00000000004004c4 <+18>:    retq   
End of assembler dump.
(gdb) break *0x00000000004004bd
Breakpoint 1 at 0x4004bd
(gdb) r
Starting program: /home/xdbeef/answer 

Breakpoint 1, 0x00000000004004bd in main ()
(gdb) info registers ebp esp
ebp            0xffffdae0          -9504
esp            0xffffdae0          -9504
(gdb) x/12xw 0x7fffffffdae0 
0x7fffffffdae0: 0x004004d0  0x00000000  0xf7a2d830  0x00007fff
0x7fffffffdaf0: 0x00000000  0x00000000  0xffffdbc8  0x00007fff
0x7fffffffdb00: 0xf7ffcca0  0x00000001  0x004004b2  0x00000000
(gdb) x/12xa 0x7fffffffdae0 
0x7fffffffdae0: 0x4004d0 <__libc_csu_init>  0x7ffff7a2d830 <__libc_start_main+240>
0x7fffffffdaf0: 0x0 0x7fffffffdbc8
0x7fffffffdb00: 0x1f7ffcca0 0x4004b2 <main>
0x7fffffffdb10: 0x0 0x716825b9b97d27b5
0x7fffffffdb20: 0x4003e0 <_start>   0x7fffffffdbc0
0x7fffffffdb30: 0x0 0x0

Now, the first address on main's stack (frame pointer) was to __libc_csu_init, and the latter (return pointer) to some place in __libc_start_main, from which the 'main' function was called.

Btw, don't have enough reputation to comment on other's answers, but user189437 posted (and not credited the original author, eh) a snippet from very good post on Patrick Horgan's blog, that explains how C applications are bootstrapped:

http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html

My another remark is: by invoking info proc map in gdb, when breakpointed at nop instruction, you'll probably see that __libc_csu_init isn't on the stack, but in the section where program instruction lies. That makes no sense, since we can't rewind stack there! Well, that's probably some part of program-startup magic, that sets initial frame pointer.

There's a book on that very specific topic, though I didn't read it, from the few pages I've seen it covers program startup (calling _start & libc_start_main ):

https://books.google.pl/books?redir_esc=y&hl=pl&id=YZIoDQAAQBAJ&q=libc+hlt#v=snippet&q=libc%20hlt&f=false

Hope that cleared things out!

Regards, Daniel

1

As far as I am aware __libc_csu_init and main are both arguments pushed onto the stack in reverse order before the call to __libc_start_main.

This example illustration also shows main on a lower adress: enter image description here