浅谈栈区
2023-12-28 04:24:09
栈区:
是用于存储函数调用和局部变量的一块内存区域。它的大小取决于编译器的设置和编译器选项。在大多数编译器中,栈区的默认大小是固定的,通常在几MB到几十MB之间。这个默认大小可以通过编译器选项进行修改。
栈区用来存储以下信息:
-
函数参数:函数参数是通过栈区来传递的,当函数被调用时,函数的参数会被按照一定的顺序依次压入栈中。
-
局部变量:函数中定义的局部变量和临时变量也是存储在栈区中的。当函数被调用时,这些变量会被分配一定的内存空间,并在函数执行结束后自动释放。
-
返回地址:函数调用过程中,函数的返回地址会被存储在栈区中,以便在函数执行结束后返回到正确的调用位置继续执行。
-
栈帧指针:栈帧指针(Frame Pointer)是一个记录当前栈帧位置的指针,它指向当前函数开头处的栈地址。用于在程序执行过程中能够准确地获取局部变量的内存位置。
? ? ?用以下代码做个简单示例:
int test(int x ,int y)
{
return 0;
}
int main()
{
int a = 120;
int b = 12;
test(a, b);
return 0;
}
在栈区内部情况大致是这样:
第一步:栈区开辟main函数的栈帧,再用两个寄存器esp和edp分别指向当前栈帧的栈顶和栈帧的起始位置确定一片栈帧大小,当前创建的main函数栈帧所以维护的是main函数
-
ESP (Stack Pointer):
ESP
是栈指针寄存器,它指向当前栈的栈顶位置。- 在函数调用时,
ESP
用于分配和释放栈空间。 - 当函数被调用时,
ESP
会向下移动,为局部变量和参数分配空间;函数返回时,ESP
会向上移动,释放函数调用时分配的栈空间。(因为栈区使用习惯是从高地址到低地址,所以向下是开辟)
-
EBP (Base Pointer):
EBP
是基址指针寄存器,通常用于指向当前函数栈帧的基址或起始位置。- 在函数内部,
EBP
的值常用于访问函数参数和局部变量(加偏移量方便访问栈帧内部的局部变量以及其他一些东西)。 - 通过
EBP
,函数可以在栈上更方便地定位和访问自己的局部数据,而不受栈指针移动的影响。 - 在函数调用时,
EBP
会被保存到栈上,以便在函数返回时能够恢复原始的EBP
值。
?第二步:main栈帧里面开辟两个变量a,b所需的内存空间
第三步:当main函数调用test 函数时,开始压栈,创建test函数的栈帧同时esp和edp指向test函数栈帧的起始和栈顶
第四步:在里面开辟形参的所需内存以及main函数返回地址方便返回
以上是函数调用在栈中的情况
当 test
函数执行完成后,程序需要进行函数返回的过程,将控制流程返回到调用函数(例如 main
函数)的正确位置。以下是函数返回的一般过程:
-
恢复栈帧:
- 在
test
函数执行完成后,程序会从test
函数的栈帧中取出保存的返回地址,这个地址指向调用test
函数的函数(比如main
函数)的下一条指令。
- 在
-
栈帧指针(EBP)的恢复:
- 如果在
test
函数调用前保存了main
函数的栈帧指针EBP
,则需要将EBP
的值恢复为先前保存的值。这是为了确保栈帧的正确操作。
- 如果在
-
栈指针(ESP)的调整:
ESP
在函数调用时会向下移动,为局部变量和参数分配栈空间。在函数返回时,ESP
需要向上移动,释放先前分配的栈空间。
-
跳转到返回地址:
- 将控制流程跳转到保存的返回地址,这样程序就会返回到调用
test
函数的函数的下一条指令处。
- 将控制流程跳转到保存的返回地址,这样程序就会返回到调用
使用栈区好处:先进后出的结构方便随用随丢(执行完当前函数如果没有再调用其他函数就销毁)以及栈区是线性回归方便寄存器的实现,栈区的内存管理相对简单,不需要手动分配和释放内存。这减少了程序员的负担,降低了出错的可能性。
文章来源:https://blog.csdn.net/weixin_61183404/article/details/135209821
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!