ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

栈溢出原理笔记(一)

2019-10-14 20:01:14  阅读:203  来源: 互联网

标签:函数 int 笔记 函数调用 var 原理 栈帧 溢出 内存


系统栈的工作原理

1.内存的不同用途
        简单来说,缓冲区溢出就是在大缓冲区的数据复制到小缓冲区中,由于没注意小缓冲区的边界,”撑爆“了小缓冲区。从而冲掉了小缓冲区相邻内存区域的数据。
根据不同的操作系统,一个进程可能被分配到不同内存区域中去执行,但是不管什么样的系统,什么计算机架构,进程使用的内存都可以按照功能分为4部分:
        代码区:可执行指令
        数据区:用于存储全局变量
        堆区:  进程可以在堆区动态的请求一定大小的内存,并在用完之后归还给堆区。动态分配和回收是堆区的特点
        栈区:  用于动态的存储函数之间的调用关系,以保证被调用函数返回时恢复到母函数中继续执行
        这只是简单的内存划分,如果想了解关于内存更详细的论述,请参考《深入理解计算机系统》,windows下,PE文件代码段中包含的二进制机器代码会被装入内存的代码区,处理器将到这里一条一条的取出指令和操作数,送入算术逻辑单元运算,如果代码请求开辟动态内存,则会在内存的堆区分配一块区域返回给代码区的代码使用,当函数调用发生时,函数的调用关系等信息会动态的保存在栈区。
程序中所使用的缓冲区可以是在堆区、栈区、数据区,不同地方的缓冲区利用方法不同。
2.栈与系统栈
        栈是一种数据结构,是一种先进后出的数据表,用于标识栈的属性两个:栈顶、栈底 。内存中的栈区指的就是系统栈,由系统自动维护。
3.函数调用时发生了什么
        请看如下C代码:
        int B(int b1,int b2){
                int var_b1=b1+b2;
                int var_b2=b1-b2;
                return var_b1*var_b2;
        }
        int A(int a1,int a2){
                int var_a1;
                var_a=B(a1,a2)+a1;
                return a1;               
        }
        int main(int argc,char **argv,char **envp){
                int var_main;
                var_main=A(4,3);
                return var_main;
        }
        根据操作系统的不同、编译器和编译选项的不同,同一文件不同函数的代码在内存代码区中的分布可能相邻,也可能不相邻,可能有先后顺序,也可能没有,但他们都是在代码所映射的节里
函数调用时,伴随的系统栈中的操作如下:
在main函数调用A的时候,首先在自己的栈帧中压入函数返回地址,然后位A创建新栈帧并压入系统栈 ,
在函数A调用B的时候,同样先在自己的栈帧中压入返回地址,然后为B创建新栈帧并压入系统栈
B返回时,B的栈帧被弹出系统栈,A栈帧的返回地址被露在栈顶,处理器跳到返回地址处执行
在A返回时,A的栈帧被弹出系统栈,main函数栈帧中的返回地址被露在栈顶。处理器跳到返回地址执行
4.寄存器与函数栈帧
        每一个函数独占自己的栈帧空间,当前正在运行的函数总是在栈顶,win32系统提供两个寄存器用于标识位于系统栈顶端的栈帧
         ESP:栈指针寄存器,存放一个指针,该指针永远指向系统栈最上面的栈帧的栈顶
         EBP:基址指针寄存器,该指针永远指向系统栈最上面的栈帧的底部
         函数栈帧:ESP和EBP之间内存空间为当前栈帧
         在函数栈帧中一般包含以下几种信息:、
         局部变量:为函数举报变量开辟的内存空间
         栈帧状态值:保存前栈帧的顶部和底部(实际上只保存前栈帧的底部,前栈帧的顶部可以通过堆栈平衡得到)
         函数返回地址:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位置
         函数栈帧的大小不固定,一般和局部变量的多少有关
5.函数调用约定与相关指令
        调用约定描述了函数传递参数的方式和栈协同工作的技术细节,下面列出几种调用方式:
                                C                Syscall                Stdcall                BASIC                FORTRAN                PASCAL
参数入栈顺序 右→左         右→左                右→左                左→右                 左→右                左→右
谁恢复栈平衡 母函数                子函数                子函数                子函数                子函数                子函数
        对于Visual C++,支持3种函数调用约定:
       
        调用约定声明                参数入栈顺序                谁恢复栈平衡
        __cdecl                                右→左                                母函数
        __fastcall                        右→左                                子函数
        __stdcall                        右→左                                子函数
        除了入栈方向和恢复平衡不同之外,参数传递有时也会有所不同。例如,每一个C++类成员函数都有一个this指针,在windows下,这个指针保存在ECX中
,但如果用GCC编译,这个指针会作为最后一个参数入栈

        函数调用大致包括以下几个步骤:
         参数入栈
         返回地址入栈
         代码区跳转
         栈帧调整:具体包括
         保存当前栈帧状态值(push ebp)
         将当前栈帧切换到新栈帧(mov ebp,esp)
         给新栈帧分配空间(把ESP减去所需空间大小,抬高栈顶)
         
        函数返回大致包括以下几个步骤:
         保存返回值(通常保存在EAX中)
         弹出当前栈帧,恢复上一个栈帧:具体包括
         在堆栈平衡的基础上给ESP加上栈帧的大小,降低栈顶,回收当前栈帧空间
         将当前栈帧底部保存的前栈帧EBP值弹入EBP,恢复出上一个栈帧
         将函数返回地址弹给EIP

    跳转

标签:函数,int,笔记,函数调用,var,原理,栈帧,溢出,内存
来源: https://www.cnblogs.com/daiorz/p/11673557.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有