1 示例代码
#include <stdio.h>int func(int param1 ,int param2,int param3)
{int var1 = param1;int var2 = param2;int var3 = param3;printf("var1=%d,var2=%d,var3=%d",var1,var2,var3);return var1;
}int main(int argc, char* argv[])
{int result = func(1,2,3);return 0;
}
2 解析
首先说明,在堆栈中变量分布是从高地址到低地址分布,EBP是指向栈底的指针,在过程调用中不变,又称为帧指针。ESP指向栈顶,程序执行时移动,ESP减小分配空间,ESP增大释放空间,ESP又称为栈指针。
2.1 调用过程
- 函数
main
执行,main
的各个参数从右往左压入栈中(这样访问参数出栈的时候是从左到右的),参数param3-param1依次压栈,如图
- 压入返回地址
- 程序执行从main跳转到被调用函数中,EBP入栈,将ESP(当前栈顶)赋值给EBP。
当一个新的函数调用的时候,首先将旧的EBP入栈,这样是为了保存当前调用者的栈帧,然后从当前栈顶开始建立新的栈帧(将当前栈顶ESP的值作为新的栈底EBP)
push ebp
mov ebp esp
此时栈顶(ESP)和栈底(EBP)指向同一位置
2.2 函数执行过程
int var1 = param1;
对应汇编如下:
mov 0x8(%ebp), %eax
mov %eax, -0x4(%ebp)
先将EBP+0x8
地址里面的内容赋值给eax,看图中EBP+0x8
刚好是param1,再把eax寄存器的内容存到ebp-0x4
的位置。这个相当于开了一个新变量int,然后赋值给这个变量。其余同理。
2.3 函数的返回
函数返回值一般存在eax寄存器中。
mov -0x4(%ebp), %eax
之后参数依次出栈,EBP恢复原值,返回到记录的返回地址,参数param1, param2,param3依次出栈,函数调用结束。