旧的EBP和退货地址在哪里?

时间:2013-07-21 19:39:30

标签: c x86 return cpu-registers

我在理解在哪里找到EBP并返回地址时遇到了一些麻烦。根据我的理解,调用sub可以为函数中的局部变量保留空间。我特别对这段代码感到困惑。

void countLines(FILE* f){
char buf[0x400];//should be big enough for anybody
int lines=0;
fread(buf,READSIZE,1,f);  

for(int i=0;i<0x400;i++)
  if(buf[i] == '\n')
    lines++;


printf("The number of lines in the file is %d\n",lines);
return;
}

用gdb反汇编这个函数后,我得到了:

0x08048484 <+0>:    push   %ebp
0x08048485 <+1>:    mov    %esp,%ebp
0x08048487 <+3>:    sub    $0x428,%esp

为什么是0x428?加上局部变量长度,我只得到0x408(char [400],行和i)。此外,EBP和返回地址是否紧跟在保留空间之后?

2 个答案:

答案 0 :(得分:3)

执行函数序言后,您的堆栈如下所示:

*****
*****
return address
old EBP   <---- EBP
.....
..F..
..r..
..e..          (0x428 bytes)
..e..
.....      <---  ESP

要从函数返回,只需将ESP恢复为EBP中保存的值,从堆栈中弹回前一个EBP,然后调用ret。这反过来会从堆栈中弹出返回地址并跳转到那里:

mov %ebp, %esp
pop %ebp
ret

(保持EBP的目的是让你不必记住你在功能期间增加了多少ESP(想想alloca)。你没有拥有使用EBP,例如使用GCC的-fomit-frame-pointer。)

答案 1 :(得分:1)

函数args(可能还有寄存器)也保存在0x428字节的空间中。此外,在调用其他函数时,GCC不会使用push / pop,而只会存储相对于esp的args(例如mov 0x4(%esp),%eax)。

所以0x428来自0x408(本地变量)+ 0x4(参数)+ 0x10(fread最多4个参数的空间)+ 0x8(可能是其他我缺少的东西,可能是寄存器)。