zoukankan      html  css  js  c++  java
  • 操作系统函数堆栈过程

    概述

    文章讲的是汇编语句中执行函数时堆栈的过程,其中比较重要的是 ESPEBP 这俩个寄存器.

    调用过程

    1297993-20220109113942875-1893306958.png

    假如让我们来设计这个函数调用的堆栈过程,我觉得可以这样思考
    现看这个函数调用 ,调用 add方法需要传过去参数 ,所以必须有一个地方可以让add函数执行形成的堆栈可以取得到 main 传过来 ,再一个 add 执行完之后还得返回main中继续执行 ,所以返回地址也是必须保存的.

    1297993-20220109114724144-660974239.png

    上面左图这是说明了,在一个进程中,堆是向下增长的, 右图则是从调用者被调用者两个角度在描述这个调用的过程..

    1297993-20220109115020494-1266243661.png

    我们常提到的IA32 寄存器就几个 , 当我要去调用下一个函数的时候, 为了腾出寄存器给即将调用的函数使用,所以调用之前我们必须先将寄存器中的数据入栈 ,这样即将调用的函数就可以使用了 (我们后面会看到保存返回地址也是这个套路 ,先将返回地址保存在栈里然后执行完函数之后的执行回到返回地址就好了)

    其中需要注意的两个寄存器 :

    • ESP (stack point) : 指向当前栈帧的顶部
    • EBP (base point) : 指向栈帧的底部

    底部是不会动的,而顶部会一直增长

    接下来看一个例子 :

    1297993-20220109120119576-1966375804.png

    1297993-20220109120257673-255875680.png

    上面的例子 ,可以看到 ESPEBP始终是指向当前栈帧的顶部和底部的, 我们可以看到大致的过程可以分为 :

    • 准备阶段
    • 过程体
    • 结束阶段

    这里注意几个细节

    每个过程开始的两条指令

    pushl %ebp
    movl %esp, %ebp
    

    意思就把调用人的 EBP 先入栈了 (方便后续执行找回来),然后将ESP 的值给到 EBP(上一句我们已经把 EBP的值存起来了,所以此时 EBP就可以用来新的函数形成的堆栈的栈底了,秒啊!) ,那我如果要让 EBP 回到我之前入栈的那个值呢?

    popl %ebp 
    

    即可.

    call 语句

    call语句做的事情有两个 :

    1. 保存返回地址
    2. 跳转执行函数
      在上面例子中, 返回地址就是 :
    movl %eax, -4(%ebp)
    

    这一语句的地址

    跳转执行函数开始的语句是什么

    还是这两句

    pushl %ebp
    movl %esp, %ebp
    

    执行函数

    1297993-20220109121745821-1032010805.png

    上面的例子我们看到执行函数的过程中 ,为了获取传进来的参数 ,可以通过 EBP 往上偏移 8或是12 ,具体的语句 :

    movl 8(%ebp),%edx
    movl (%edx),%ecx 
    
    

    返回

    ret 实际会把前面入栈的返回地址放在 EIP 寄存器 ,这样就可以回到调用函数的下一句啦.(IA32中用EIP存放将要执行的地址)

    简图

    1297993-20220111225222189-1734534709.png

    参考

  • 相关阅读:
    宅急送
    网站迁移主要工作完成
    服务器迁移后性能提升很明显
    Vista修改默认字体
    服务器迁移预告
    Silverlight 2 和 Deep Zoom
    Mix 08到来之前的Monolight Update
    ASP.NET MVC Preview生命周期分析
    Windows Server 2008 与 .NET Framework 的版本之间有什么关系
    Silverlight 2 DispatcherTimer和通过XAML创建UI元素
  • 原文地址:https://www.cnblogs.com/Benjious/p/15790509.html
Copyright © 2011-2022 走看看