函数栈桢的创建和销毁

函数栈桢的创建和销毁

  • 一、解决的问题
  • 二、认识常用的寄存器及其指令操作
  • 三、函数栈桢解析
  • 三、回答问题

一、解决的问题

1.局部变量是怎么创建的?
2.为什么局部变量的值是随机值?
3.函数是怎么传参的?传参的顺序是怎样的?
4.形参和实参是什么关系?
5.函数调用是怎么做的?
6.函数调用是结束后怎么返回的?
7.return语句的本质是什么?

二、认识常用的寄存器及其指令操作

1.常用寄存器
eax:通用寄存器,保留临时数据,常用于返回值
ebx:通用寄存器,保留临时数据
ebp:栈底寄存器
esp:栈顶寄存器
eip:指令寄存器,保存当前指令的下一条指令的地址

2.常用指令
mov:数据转移指令
push:数据入栈,同时esp栈顶寄存器也要发生改变
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
sub:减法命令
add:加法命令
call:函数调用,1. 压入返回地址 2. 转入目标函数
jump:通过修改eip,转入目标函数,进行调用
ret:恢复返回地址,压入eip,类似pop eip命令

三、函数栈桢解析

  栈区(stack):1.在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内存容量有限。 栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等。
我的评价是:是说人话,虽然我现在理解的不是很清楚,栈这个区域是函数栈桢开辟的一块空间,在这一块空间里面主要是为函数来服务的,比如在函数内存的局部变量,函数的参数,函数的返回值,返回的地址,这些都是在栈这个空间服务的。至于说“”“栈内存分配运算内置于处理器的指令集中”这句话,我现在还感受不到,学的知识太浅,下来问老师。
函数栈桢的创建和销毁_第1张图片
下面我详细介绍函数栈桢的开辟与销毁过程,有写汇编指令看不懂,但是不影响看懂整个流程
函数栈桢的创建和销毁_第2张图片
先说一下,两个重要的寄存器,esp是栈顶寄存器,也就是存储栈顶地址的寄存器,ebp是栈底寄存器,这个寄存器维护的区域就是函数栈开辟的区域。
下面是在vs2022,x86下函数的开辟过程。
首先明白main也是函数,也是在栈区占用了一块空间,main函数是函数,它也是要被其它函数调用启动,具体是一个__tmainCRTStartup这个函数来调用main,在这一点具体的细节不讨论,以后学的知识多了在说。
看汇编代码,首先是把__tmainCRTStartup这个函数的栈底的地址压栈,存入栈区,为的是在函数返回过来,能够找到这个地方,然后是esp和ebp指向同一块区域,esp-0e4h,esp向上指,开辟了288个字节的空间给main函数的栈桢,之后ebx,esi,edi入栈,下来在main函数开辟的栈区,初始化了一部分空间,我上面的例子初始化了36个字节(填充为0xcc),然后给a,b,c三个变量开辟了空间,这个以8个字节为一部分向上开辟,这部分完了之后,就要对Add函数进行操作,特别重要函数栈桢的创建和销毁_第3张图片
先把形参入栈,在把形参x入栈,下来是在执行call指令的同时,把call指令的下一条指令地址入栈,方便返回,然后把main函数的栈底地址入栈,为的是能够找到main的栈底,然后又把ebp指向esp指向的地方,esp-0cch,给Add函数栈桢204个字节,还是ebx,esi,edi入栈,之后初始化一部分空间,这儿初始化了12个字节,之后给z开辟空间,通过eax寄存器把x和y取出来,运用add指令相加之后放到了z里面,而return的操作是把z的值给eax寄存器,通过eax寄存器把它带出来了,之后edi,exi,ebx出栈,之后,esp回到ebp的地方,在pop ebp,ebp回到main函数的栈底,维护main函数,由于以前把call的下一条指令地址压栈了,ret语句执行,esp-4,返回到call的下一条指令执行(这个call的返回可能是程序寄存器来完成),esp+8跳过两个形参x,y,esp来到main函数的栈顶,至此,分析完毕,esp和ebp又维护main函数的栈桢了。

三、回答问题

1.局部变量是怎么创建的?
*局部变量的创建是先给函数开辟空间,指的是esp和ebp之间的空间,然后在这一块空间里,给局部变量开辟空间。
2.为什么局部变量的值是随机值?
*在给函数一部分空间之后,要对这部分空间进行初始化,初始化给内存中填的值就是随机值。
3.函数是怎么传参的?传参的顺序是怎样的?
函数传参是在函数栈桢空间未分配之前,就已经通过压栈操作,把形参压入栈中,是从右向左压栈,取出正好是从左向右。
4.形参和实参是什么关系?
实参就是在函数栈桢内创建的,形参是压入栈中的,两个不是同一个空间,是完全不同的两块空间。
5.函数调用是怎么做的?
函数调用是在函数形参压入栈中,当需要参数来计算时,是通过寄存器(eax)把压入中的形参拿出来,进行使用。
6.函数调用是结束后怎么返回的?
函数在调用之前就已经把call的下一条指令的地址压入栈中了,函数调用结束后,通过ret指令,返回到call的下一条指令。
7.return语句的本质是什么?
return语句是通过寄存器eax把值带出函数的!

你可能感兴趣的:(学习,c语言)