首页 » 信息技术 »

局部变量与函数调用栈

2019年11月22日 / 4次阅读
CC++

不知道从什么时候开始,运行在OS内的程序文件,有了规范,Win系统下是PE,Linux系统下是ELF。符合规范的程序能够被OS调用并执行。

不知道从什么时候开始,程序在OS的管控下执行,每个进程都有自己的堆(heap)和栈(stack)。堆的地址从小到大,存放需要程序代码显式申请的内存块,并且也需要程序自己管理和释放。栈的地址从大到小,存放函数调用过程中的指令地址和函数的局部变量。程序员需要关注堆的管理,但是栈的相关操作,由编译器完成。

在栈中存放程序返回的地址,这个是很好理解的。在栈中存放函数的局部变量,并且在函数执行完后释放这部分空间,我理解这是当初的一个很精妙的软件设计。与全局变量存放在.data数据区不同,函数仅自己使用的变量由于只有短暂的生命周期,如果使用像堆一样显式地申请和释放的方式,必然会增加程序员的代码工作量,也会增加软件出错的概率。因此,这些函数自己使用的变量,就放在了栈中,由编译器自动完成在栈中的空间申请,赋初值和释放的动作。

CPU很配合,对于这些已经成为标准的软件设计概念,贡献出对应的寄存器来支持!

刚才是一点个人的牢骚,本文后面主要记录一些关于函数调用栈的知识点。

关于压栈出栈的不同方式

对于函数调用时的压栈和出栈,其实在细节上有一些不同的实现方式,如下图,据说是VC++的标准:

几种不同的压栈出栈方式

几种不同的压栈出栈方式

C的标准,应该就是从右到左压栈,这样的效果是,最右边的参数地址,在高地址。

一个函数调用压栈出栈的具体细节

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

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

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

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

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

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

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

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

<4>对于_stdcall调用约定,函数调用时用到的指令序列大致如下:

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)让处理器跳转到弹出的返回地址,恢复调用前代码区

一个有函数局部变量示意的调用栈图

函数调用栈

函数调用栈

系统栈

OS负责不同进程的切换,每个进程都有自己的栈,编译好的程序,都能自己管理好自己的栈。

CPU层面也有栈,这个栈是系统栈。比如在有中断的时候,CPU也需要跳转到其它地方去执行别的指令,这时也需要压栈和出栈。压栈保存CPU执行现场,即各种寄存器的值;出栈就是恢复执行现场。对应的机器指令有call,ret,push和pop。

注意CPU的各类jmp指令,它就是条件跳转,与压栈出栈无关。因为各种jmp指令,使得我们可以直接在高级语言中实现各种程序执行控制。

以上就是本人对函数调用栈和函数的局部变量的一点总结。

本文链接:https://www.maixj.net/ict/local-stack-23097

相关文章

留言区


前一篇:
后一篇:

栏目精选

云上小悟,麦新杰的独立博客

Ctrl+D 收藏本页

栏目


©Copyright 麦新杰 Since 2014 云上小悟独立博客版权所有 备案号:苏ICP备14045477号-1。云上小悟网站部分内容来源于网络,转载目的是为了整合信息,收藏学习,服务大家,有些转载内容也难以判断是否有侵权问题,如果侵犯了您的权益,请及时联系站长,我会立即删除。

网站二维码
go to top