我在理解在哪里找到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和返回地址是否紧跟在保留空间之后?
答案 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
)。你没有拥有例如,em>使用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(可能是其他我缺少的东西,可能是寄存器)。