栈区

栈区

         内存中的栈区实际上类似于数据结构中的栈。两者区别的是数据结构中的栈是解决为程序开发而设计的算法问题(例迷宫求解问题),而在内存中的栈区是解决内存分配的问题(以前堆栈的说法就是指内存的栈区,也叫系统栈)。不过,它们俩相同点就是遵守先进后出的规则下面讲解的是程序运行时候所说的栈区,并不特指定目标文件的栈段。

栈区的组成部分:在栈区里面其实又可以分成好几个区域,他们叫做栈桢,一个栈桢就是一个函数,需要调用该函数的时候就入栈,函数return的时候就会弹出栈,所以他们的生命周期从这个函数开始到函数结束。

栈桢里面存放这以下几种东西:参数变量的地址、局部变量的地址、return的地址、栈指针和基指针等。

 栈区有重要的寄存器:

栈顶指针寄存器ESP:永远指向栈桢的栈顶的指针

基址寄存器EBP(栈底寄存器EBP):永远指向栈桢的底部。存取某时刻的栈顶指针,以方便对咋还能的操作,如获取函数参数、局部变量等 。

eax寄存器:一般用来保存函数的返回值关于栈寄存器的知识,下面会提到的

栈有两个基本操作:入栈(也叫压栈)和出栈(也叫弹栈)。

由栈区分为几个小区域--几个栈桢(也就是函数)也称为函数栈。所以调用某函数的时候,函数栈也遵守栈的先进后出的规则。

以下的例子是函数1、函数2和函数3逐步被调用的情况:

(其中因为主函数main作为程序入口,是第一个被放进栈里面的。以下是两种代码中的被调用函数入栈的顺序是不一样的,自己分析一下)

代码一和图解: 

栈区_第1张图片栈区_第2张图片

代码二和图解

   栈区_第3张图片栈区_第4张图片

函数fun1内部的自动变量以及形参的入栈情况:

函数fun1内部的变量int d如果放改变在fun2()后面,分配的地址是一样的。因为栈区分了几个区域(函数栈),一个函数栈里面包含所有自动变量都是放在同样函数栈区域的。

形参和实参的入栈顺序是这样子的:

fun1(int a,int b )和int c,d的入栈顺序是按照自右向左读取,所以地址:右边的变量地址>左边的变量地址。(向低地址生长入栈)

(改正:下面的代码中:把注释“当int b放在...”改为“当int d放在... ”)

栈区_第5张图片

函数栈1的各个变量入栈与出栈图解:

栈区_第6张图片

以下一段文字来自于某博客文章的内容(还是别人写得好):

*-------------------------------------------内容界线---------------------------------------

函数调用大概包括以下几个步骤:

(1)参数入栈:将参数从右向左依次压入系统栈中。

(2)返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。

(3)代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。

(4)栈帧调整:具体包括:

<1>保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)。

<2>将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部)。

<3>给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶)。

<4>对于_stdcall调用约定,函数调用时用到的指令序列大致如下:(push是入栈,pop出栈

push 参数3 ;假设该函数有3个参数,将从右向做依次入栈

push 参数2

push 参数1

call 函数地址 ,call指令将同时完成两项工作:

a)向栈中压入当前指令地址的下一个指令地址,即保存返回地址。

 b)跳转到所调用函数的入口处。

push ebp ;保存旧栈帧的底部

mov ebp,esp ;设置新栈帧的底部 (栈帧切换)

sub esp,xxx ;设置新栈帧的顶部 (抬高栈顶,为新栈帧开辟空间)

函数返回的步骤如下:

<1>保存返回值,通常将函数的返回值保存在寄存器EAX中。

<2>弹出当前帧,恢复上一个栈帧。具体包括:

(1)在堆栈平衡的基础上,给ESP加上栈帧的大小,降低栈顶,回收当前栈帧的空间。

(2)将当前栈帧底部保存的前栈帧EBP值弹入EBP寄存器,恢复出上一个栈帧。

(3)将函数返回地址弹给EIP寄存器。

<3>跳转:按照函数返回地址跳回母函数中继续执行。

还是以C语言和Win32平台为例,函数返回时的相关的指令序列如下:

add esp,xxx ;降低栈顶,回收当前的栈帧

pop ebp ;将上一个栈帧底部位置恢复到ebp

retn ;a)弹出当前栈顶元素,即弹出栈帧中的返回地址,至此,栈帧恢复到上一个栈帧工作完成。b)让处理器跳转到弹出的返回地址,恢复调用前代码区

5.寄存器与函数栈帧
每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。Win32系统提供两个特殊的寄存器用于标识位于系统栈顶端的栈帧。

(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

栈区_第7张图片

 

 

你可能感兴趣的:(内存管理)