是用于存储函数调用和局部变量的一块内存区域。它的大小取决于编译器的设置和编译器选项。在大多数编译器中,栈区的默认大小是固定的,通常在几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;
}
ESP (Stack Pointer):
ESP
是栈指针寄存器,它指向当前栈的栈顶位置。ESP
用于分配和释放栈空间。ESP
会向下移动,为局部变量和参数分配空间;函数返回时,ESP
会向上移动,释放函数调用时分配的栈空间。(因为栈区使用习惯是从高地址到低地址,所以向下是开辟)EBP (Base Pointer):
EBP
是基址指针寄存器,通常用于指向当前函数栈帧的基址或起始位置。EBP
的值常用于访问函数参数和局部变量(加偏移量方便访问栈帧内部的局部变量以及其他一些东西)。EBP
,函数可以在栈上更方便地定位和访问自己的局部数据,而不受栈指针移动的影响。EBP
会被保存到栈上,以便在函数返回时能够恢复原始的 EBP
值。第三步:当main函数调用test 函数时,开始压栈,创建test函数的栈帧同时esp和edp指向test函数栈帧的起始和栈顶
以上是函数调用在栈中的情况
当 test
函数执行完成后,程序需要进行函数返回的过程,将控制流程返回到调用函数(例如 main
函数)的正确位置。以下是函数返回的一般过程:
恢复栈帧:
test
函数执行完成后,程序会从 test
函数的栈帧中取出保存的返回地址,这个地址指向调用 test
函数的函数(比如 main
函数)的下一条指令。栈帧指针(EBP)的恢复:
test
函数调用前保存了 main
函数的栈帧指针 EBP
,则需要将 EBP
的值恢复为先前保存的值。这是为了确保栈帧的正确操作。栈指针(ESP)的调整:
ESP
在函数调用时会向下移动,为局部变量和参数分配栈空间。在函数返回时,ESP
需要向上移动,释放先前分配的栈空间。跳转到返回地址:
test
函数的函数的下一条指令处。使用栈区好处:先进后出的结构方便随用随丢(执行完当前函数如果没有再调用其他函数就销毁)以及栈区是线性回归方便寄存器的实现,栈区的内存管理相对简单,不需要手动分配和释放内存。这减少了程序员的负担,降低了出错的可能性。