函数调用堆栈的过程(转载收藏)

函数调用堆栈的过程(转载收藏)

原文链接:https://blog.csdn.net/qq_41431406/article/details/96446312

#include<stdio.h>
int sum(int a,int b)
{
	int tmp=0;
	tmp=a+b;
	return tmp;
}
 
int main()
{
	int a=10;
	int b=20;
	int ret=0;
 
	ret=sum(a,b);
	printf("ret=%d\n",ret);
	return 0;
}

反汇编如下所示:

解析后的反汇编:

画出在栈中的整个过程:

  • 总结:
  • 1、函数的运行都是在栈上开辟内存。
  • 2、栈是通过esp(栈顶指针)、ebp(栈底指针)两个指针来标识的。
  • 3、对于栈上的访问都是通过栈底指针的偏移来访问的。
  • 4、在call一个函数时,有两件事情要做:先将调用函数的下一行指令的地址压入栈中;再进行跳转。
  • 5、在函数调用时检查函数是否申明、函数名是否相同、函数的参数列表是否匹配、函数的返回值多大。

    ①如果【函数的返回值<=4个字节】,则返回值通过寄存器eax带回。
    ②如果【4<函数的返回值<=8个字节】,则返回值通过两个寄存器eax和edx带回。
    ③如果【函数的返回值>8个字节】,则返回值通过产生的临时量带回。

  • 6、函数结束ret指令干了两件事:先出栈;再将出栈的值放到CPU的PC寄存器中。因为PC寄存器中永远放的是下一次执行指令的地址,所以就顺理成章的在函数调用完之后依旧接着原来的代码继续执行。

函数调用:

    #include<stdio.h>
    int sum(int a,int b)
    {
    	/*
    	push ebp
    	mov ebp,esp
    	sub esp,44h
    	push ebx
    	push esi
    	push edi
    	lea edi,[ebp-44h]
    	mov ecx,11h
    	mov eax,0xccccccch
    	rep stos ===>[esp,ebp]=0xcccccccc
    	*/
    	int tmp=0;//mov dword ptr[ebp-4],0
    	tmp=a+b;
    	/*
    	mov eax,dword ptr[ebp+8]
    	add eax,dword ptr[ebp+0ch]
    	mov dword ptr[ebp-4],eax
    	*/
    	return tmp;//mov dword ptr[ebp-4],eax
    }
    /*
    mov eax,dword ptr[ebp-4]
    mov esp,ebp
    pop ebp
    ret
    */
     
    int main()
    {
    	/*
    	push ebp
    	mov ebp,esp
    	sub esp,44h
    	push ebx
    	push esi
    	push edi
    	lea edi,[ebp-44h]
    	mov ecx,11h
    	mov eax,0xccccccch
    	rep stos ===>[esp,ebp]=0xcccccccc
    	*/
    	int a=10;//mov dword ptr[ebp-4],0Ah
    	int b=20;//mov dword ptr[ebp-8],14h
    	int ret=0;//mov dword ptr[ebp-0Ch],0
    	ret=sum(a,b);
    	/*
    	mov eax,ptr[ebp-8]
    	push eax
    	mov ebx,ptr[ebp-4]
    	push ebx
    	push ecx
    	call sum
    	add esp,8
    	mov dword ptr[ebp-0ch],eax
    	*/
    	printf("ret=%d\n",ret);
    	return 0;
     
    }

简单过程:
1:压入实参 形参初始化 自右向左
2:压下一行指令地址
3:压调用方栈底地址
4:跳转到被调用方函数栈帧
5:被调用方函数活动开辟空间

posted @ 2020-05-05 22:11  虹澄清晓  阅读(697)  评论(0编辑  收藏  举报
页尾