2

我无法理解在哪里可以找到 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 和返回地址?

4

2 回答 2

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

于 2013-07-21T19:43:42.613 回答
1

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

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

于 2013-07-21T20:43:29.667 回答