I am trying to write a buffer overflow exercise in c for students.
Typically, a stack frame consists of function parameters, return address, base pointer, and local variables. But I found that sometimes additional registers are stored along with the base pointer. I remember from the class that cached registers must be saved before they are used. But there are times when compiling C code creates an assembly that saves and uses registers apperently for no purpose. Please explain this behavior to me.
Assume the main function
int main (int argc, char** argv) { func(); return 0; }
and function
void func() { char buf[5]; strcpy(buf,"AAAA"); strcpy(buf,"BBBB"); }
If I debug the resulting executable with gdb
break func run info frame
everything is fine and the stack frame contains only ebp and eip.
If i use
void func() { char buf[5]; gets(buf); }
I get
Saved registers: ebx at 0xffffd1cc, ebp at 0xffffd1d0, eip at 0xffffd1d4
So, ebx is additionally stored in the stack frame? What for? If I run
disas func
I get
Dump of assembler code for function func: 0x56555730 <+0>: push %ebp 0x56555731 <+1>: mov %esp,%ebp 0x56555733 <+3>: push %ebx 0x56555734 <+4>: sub $0x8,%esp 0x56555737 <+7>: call 0x5655576e <__x86.get_pc_thunk.ax> 0x5655573c <+12>: add $0x18c4,%eax => 0x56555741 <+17>: lea -0x9(%ebp),%edx 0x56555744 <+20>: push %edx 0x56555745 <+21>: mov %eax,%ebx 0x56555747 <+23>: call 0x56555590 < gets@plt > 0x5655574c <+28>: add $0x4,%esp 0x5655574f <+31>: nop 0x56555750 <+32>: mov -0x4(%ebp),%ebx 0x56555753 <+35>: leave 0x56555754 <+36>: ret End of assembler dump.
Thus, ebx is saved. OK. But what is it used for? eax moves to ebx before gets () is called. But it is not used afterwards. The old ebx has just been rebuilt from the stack before leaving and returning. It seems useless. Btw. What is all the call get_pc_thunk
?
Comparable behavior if I use printf instead of get:
void func() { char buf[5]; strcpy(buf, "AAAA"); printf("%s",buf); }
Gdb output:
(gdb) info frame Stack level 0, frame at 0xffffd1d8: eip = 0x56555741 in func (/home/mischa/stuff/test/test.c:35); saved eip = 0x56555779 called by frame at 0xffffd1e0 source language c. Arglist at 0xffffd1d0, args: Locals at 0xffffd1d0, Previous frame sp is 0xffffd1d8 Saved registers: ebx at 0xffffd1cc, ebp at 0xffffd1d0, eip at 0xffffd1d4 (gdb) disas func Dump of assembler code for function func: 0x56555730 <+0>: push %ebp 0x56555731 <+1>: mov %esp,%ebp 0x56555733 <+3>: push %ebx 0x56555734 <+4>: sub $0x8,%esp 0x56555737 <+7>: call 0x56555780 <__x86.get_pc_thunk.ax> 0x5655573c <+12>: add $0x18c4,%eax => 0x56555741 <+17>: movl $0x41414141,-0x9(%ebp) 0x56555748 <+24>: movb $0x0,-0x5(%ebp) 0x5655574c <+28>: lea -0x9(%ebp),%edx 0x5655574f <+31>: push %edx 0x56555750 <+32>: lea -0x17f0(%eax),%edx 0x56555756 <+38>: push %edx 0x56555757 <+39>: mov %eax,%ebx 0x56555759 <+41>: call 0x565555a0 < printf@plt > 0x5655575e <+46>: add $0x8,%esp 0x56555761 <+49>: nop 0x56555762 <+50>: mov -0x4(%ebp),%ebx 0x56555765 <+53>: leave 0x56555766 <+54>: ret End of assembler dump.
Can someone explain this to me?
I use cmake to compile with the following CMakeLists.txt:
cmake_minimum_required (VERSION 2.8)
cmake seems to be using gcc.