函数调用过程的栈帧

 
 
用一段简单的代码来看一下main函数是怎样调用的别的函数的

#include <stdio.h>

int myfunction(int x,int y)
{
int z = x+y;
return z;
}
int main()
{
int a = 0xaaaaaaaa;
int b = 0xbbbbbbbb;
int c = myfunction(a,b);
printf("将会运行到这里 ret = %d",c);
return 0;
}

反汇编之后





其中有三个最重要的寄存器要介绍一下,EBP、ESP、EIP。

其中EBP是基址寄存器,用来存放指针,指向栈底。

ESP是栈指针寄存器,用来存放指针,指向栈顶。

EIP也叫IP或PC是程序计数器,用来保存当前正在执行指令的下一条指令的地址。

还有两个较复杂的命令,call和ret.

call命令的作用1.调用函数时通过修改EIP实现函数的跳转()2.将下一条指令的地址保存在EIP,返回值压入栈中

开始时,EBP指向栈底,EIP栈顶。

当运行到箭头的位置时

mov是将b移动到了EAX寄存器中,并压栈(先进去的后出,换言之压数据和出数据都是从栈顶)

如图

同理a也是

执行call指令时先把下一条指令的地址保存起来并压入栈中。


再通过修改EIP实现函数跳转(JMP)



PUSH ebp是将ebp中内容即main函数的代码压入栈顶。


mov ebp,esp之后原来的ebp也指向了esp的位置


sub命令让esp下移了一段为myfunction函数开辟了一段空间


其余的就是对内容进行初始化,直接走到int z = x+y

mov eax,dword ptr [x]将x的内容aaaaaaaa放到eax中

add将x和y加起来放入eax中

mov将eax 的值放到z中,z的地址是ebp-8


mov dword ptr[z]将z放入eax中

与之前push相对的pop

mov esp,ebp将ebp的内容放到esp中,此时esp的内容也变成了ebp

pop ebp是把ebp指向内存单元的内容即main:code放入寄存器中并使ebp指向008ff9a8



ret 函数调用完成返回原来的位置,eip中将会保存原来的地址00be1429

出栈后栈顶回退


add esp,8即esp+8


mov eax中的内容到c中


到此main函数调用myfunction函数就结束了。






猜你喜欢

转载自blog.csdn.net/jane_yao/article/details/78523887