当调用(call)一个函数时,主调函数将声明中的参数表以逆序压栈,然后将当前的代码执行指针(eip)压栈,跳转到被调函数的入口点。
进入被调函数时,函数将esp减去相应字节数获取局部变量存储空间。被调函数返回(ret)时,将esp加上相应字节数,归还栈空间,弹出主调函数压在栈中的代码执行指针(eip),跳回主调函数。再由主调函数恢复到调用前的栈。
为了访问函数局部变量,必须有方法定位每一个变量。变量相对于栈顶esp的位置在进入函数体时就已确定,但是由于esp会在函数执行期变动,所以将esp的值保存在ebp中,并事先将原ebp的值压栈保存,以声明中的顺序(即压栈的相反顺序)来确定偏移量。
访问函数的局部变量和访问函数参数的区别:
局部变量总是通过将ebp减去偏移量来访问,函数参数总是通过将ebp加上偏移量来访问。对于32位变量而言,第一个局部变量位于ebp-4,第二个位于ebp-8,以此类推,32位局部变量在栈中形成一个逆序数组;第一个函数参数位于ebp+8,第二个位于ebp+12,以此类推,32位函数参数在栈中形成一个正序数组。
函数的返回值不同于函数参数,可以通过寄存器传递。如果返回值类型可以放入32位变量,比如int、short、char、指针等类型&