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.
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