系统栈与函数调用

原创 2015年11月21日 09:50:26

0x00 系统栈的工作原理

1) 进程使用的内存

  • 代码区:二进制机器代码
  • 数据区:全局变量等
  • 堆区:进程动态请求内存,用完归还。如动态分配和回收
  • 栈区:用于动态存储函数间调用关系,也叫系统栈、调用栈,由系统自动维护

2) 系统栈

int func_B(int arg_B1, int arg_B2)
{
    int var_B1, var_B2;
    var_B1=arg_B1+arg_B2;
    var_B2=arg_B1-arg_B2;
    return var_B1*var_B2;
}

int func_A(int arg_A1, int arg_A2)
{
    int var_A;
    var_A = func_B(arg_A1,arg_A2) + arg_A1 ;
    return var_A;
}

int main(int argc, char **argv, char **envp)
{
    int var_main;
    var_main=func_A(4,3);
    return var_main;
}
  • 程序中使用的缓冲区可以是堆区、栈区、存静态变量的数据区
  • 同一文件不同函数的代码在内存代码区的分布是散乱无关的
  • 程序执行中函数调用与系统栈的变化
    这里写图片描述
    这里写图片描述

3) 寄存器与函数栈帧

  • 当前运行函数的栈帧总在系统栈顶端
  • 当前栈帧(系统栈顶端)由ESP和EBP标识
    ESP:栈指针寄存器,存放着指向顶端栈帧的栈顶的指针
    EBP:基址指针寄存器,存放着指向顶端栈帧的底部的指针
    这里写图片描述
  • 函数栈帧包含
    局部变量:保存局部变量
    栈帧状态值:保存当前栈帧的顶部和底部
    函数返回地址:函数结束后返回到之前的代码区继续执行
  • 函数栈帧的大小不固定,与函数局部变量多少有关。函数运行过程中栈帧的大小也在变
  • EIP:指令寄存器,存着指向下一条等待执行指令的指针。

0x01 函数调用

1) 函数调用约定与相关指令

  • 函数调用约定:描述了函数参数传递方式和栈协同工作的技术细节。包括:
    a) 参数传递方式是寄存器还是压栈
    b) 栈传递时,参数压栈顺序
    c) 清栈由调用方还是被调方进行
  • 不同OS、语言、编译器的函数调用约定有差别
    这里写图片描述
    Visual C++6.0可支持3种函数约定,默认使用_cdecl调用方式
    这里写图片描述
    _fastcall方式在参数较少时通过寄存器传参:参数多时,前两个用寄存器传参,其余用压栈的方式传递
    这里写图片描述

2) 函数调用步骤

  • 参数入栈:参数从右向左依次压入栈中
  • 返回地址入栈:当前代码区调用指令的下一条指令地址压入栈,供函数返回是继续执行
  • 代码区跳转:CPU从当前代码区跳转到被调用函数的入口
  • 栈帧调整
    a) EBP入栈:保存当前栈帧状态值,以备后面恢复本栈帧时使用
    b) ESP—>EBP:更新栈帧底部,切换到新栈帧
    c) ESP – 新栈帧大小:抬高栈顶,给新栈帧分配空间
    这里写图片描述
  • OllyDbg中栈帧是按前栈帧EBP值划分的,返回地址成了栈帧顶部数据
    这里写图片描述
    这里写图片描述

3) 函数返回步骤

  • 保存返回值:函数返回值保存在EAX寄存器
  • 弹出当前栈帧,恢复上一个栈帧
    a) ESP + 当前栈帧大小:堆栈平衡基础上,降低栈顶,回收当前栈帧空间
    b) POP EBP:前栈帧EBP弹给EBP,恢复上一个栈帧
    c) POP EIP:函数返回地址弹给EIP
    这里写图片描述
    这里写图片描述
  • 跳转:按EIP的值返回母函数继续执行

4) 函数调用实现

  • 这里写图片描述

——《0day安全》学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。

函数调用栈 剖析+图解

栈: 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意...
  • wangyezi19930928
  • wangyezi19930928
  • 2013年11月25日 16:12
  • 18297

Linux下的函数调用原理—栈帧

首先我们先来看一段代码 #include #include #include void fun() { printf("haha  \n"); sleep(2); printf...
  • zw_1510
  • zw_1510
  • 2016年06月11日 22:47
  • 403

函数调用栈的获取原理分析

上一篇文章《在Linux程序中输出函数调用栈》,讲述了在Linux中如何利用backtrace获取调用栈,本篇文章主要介绍一下获取函数调用栈的原理,并给出相应的实现方式。 要了解调用栈,首先需要...
  • study_live
  • study_live
  • 2015年01月29日 17:56
  • 1458

函数调用与栈、堆

1) 在栈上创建。在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,一般使用寄存器来存取,效率很高,但是分配的内存容量有限...
  • ricefcc
  • ricefcc
  • 2014年10月22日 09:31
  • 2994

x86函数调用堆栈的操作

这篇blog试图讲明当一个c函数被调用时,一个栈帧(stack frame)是如何被建立,又如何被消除的。这些细节跟操作系统平台及编译器的实现有关,下面的描述是针对运行在Intel奔腾芯片上Lin...
  • u013982161
  • u013982161
  • 2016年12月31日 18:15
  • 391

数据结构之---栈和递归&函数调用

更正:以下所指ebx应改为eax。 EBX指“基地址”寄存器,在内存寻址时存放基地址;、 EAX是累加器(accumulator),一般用来保存函数的返回值。首先说说递归的实现和栈的关系吧,这里引...
  • github_35681219
  • github_35681219
  • 2016年09月11日 17:11
  • 1126

[C++]函数调用栈

函数调用时发生栈内存上的,这里主要涉及几个元素,函数调用,被调函数,函数参数。 涉及的过程主要有使用堆栈传递函数参数、保存返回地址、临时保存寄存器原有值(即函数调用的上下文)以备恢复以及存储本地局部...
  • whzyb1991
  • whzyb1991
  • 2015年09月12日 16:40
  • 634

C/C++函数调用过程--函数栈(二)

上一篇比较简单的理解函数调用时的参数进出栈,这里转载一篇别人的文章,通过汇编比较完整的讲解进出栈的过程。看是看觉得略难理解,但仔细看完很有收获。 函数调用--函数栈 函数调用大家都不陌生,调用...
  • suhuaiqiang_janlay
  • suhuaiqiang_janlay
  • 2015年04月23日 17:18
  • 2811

函数调用 压栈的工作原理

   1.开篇   本篇文章着重写的是系统中栈的工作原理,以及函数调用过程中栈帧的产生与释放的过程,有可能名字过大,如果不合适我可以换一个名字,希望大家能够指正,小丁虚心...
  • u011555996
  • u011555996
  • 2017年04月17日 15:11
  • 1096

C语言函数调用及栈帧结构

一、地址空间与物理内存 (1)地址空间与物理内存是两个完全不同的概念,真正的代码及数据都存在物理内存中。 物理储存器是指实际存在的具体储存器芯片,CPU在操纵物理储存器的时候都把他们当做内存来对待...
  • qq_29403077
  • qq_29403077
  • 2016年11月17日 19:10
  • 2419
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:系统栈与函数调用
举报原因:
原因补充:

(最多只允许输入30个字)