zoukankan      html  css  js  c++  java
  • 栈与调用惯例

    1.栈

        栈被定义为一个特殊的容器,用户可以将数据压入栈中,也可以将栈中的数据弹出,而且要遵循先进后出(FILO)的原则。在计算机系统中,栈是具有以上属性的动态内存区域。程序可以将数据压入栈中,也可以将数据从栈顶弹出。

        在经典的操作系统里,栈从高地址向低地址增长,在i386下,栈顶由esp寄存器进行定位。压栈使栈顶地址减小,弹出使栈顶地址增大。

    image

    栈在程序运行过程中具有举足轻重的地位。栈保存了一个函数调用所需要维护的信息,这常常被称为堆栈帧或活动记录。一般包括以下几个方面:

    • 函数的返回地址和参数。
    • 临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
    • 保存的上下文:包括在函数调用前后需要保持不变的寄存器。

    一个常见的活动记录如下图所示:

    image

    一个函数的活动记录由ebp和esp两个寄存器划定范围。esp寄存器始终指向栈的顶部,同时也就指向了当前函数的活动记录的顶部。ebp寄存器指向了函数活动记录的一个固定位置,被称为帧指针。固定不变的ebp可以用来定位函数活动记录中的各个数据。例如函数返回地址的地址为ebp+4,再往前是压入栈中的参数,地址分别是ebp+8,ebp+12等,视参数数量和大小而定。ebp所直接指向的值是调用该函数前ebp的值,这样在函数返回的时候,ebp可以通过读取这个值恢复到调用前的值。

    在i386下函数调用的过程:

    • 把所有或一部分参数压入栈,如果有其他参数没有入栈,那么使用某些特定的寄存器传递。
    • 把当前指令的下一条指令的地址压入栈中。
    • 跳转到函数体执行。
    • push ebp。
    • mov ebp,esp:esp=ebp。
    • 【可选】sub esp,XXX:在 栈上分配XXX字节的临时空间。
    • 【可选】push XXX:如有必要,保存名为XXX寄存器。
    • 【可选】pop XXX:恢复保存过的寄存器。
    • mov ebp,esp:esp=ebp,恢复ESP同时回收局部变量空间。
    • pop ebp:从栈中恢复保存的ebp的值。
    • ret:从栈中取得返回地址,并跳转到该位置。

    2.调用惯例

    函数的调用方和被调用方对于函数如何调用必须有一个明确的约定,只有双方都遵守同样的约定,函数才能被正确的调用,这样的约定就称为调用惯例。

    调用惯例包含以下几个方面的内容:

    • 函数参数的传递顺序和方式。顺序:从左向右或从右向左;方式:栈传递或寄存器传递。
    • 栈的维护方式。是指栈中数据弹出的过程,可以有函数的调用方来完成,也可以由函数本身完成。
    • 名字修饰策略。为了链接的时候对调用惯例进行区分,调用惯例要求对函数本身的名字进行修饰。

    几种主要的调用惯例:

    无标题

  • 相关阅读:
    Python初学者第十天 集合、十六进制
    Python初学者第九天 字符串、列表、字典练习
    Python初学者第八天 元组和字典
    Python初学者第七天 字符串及简单操作
    Python初学者第六天 列表操作练习
    Python初学者第五天 列表及简单操作
    Python初学者第四天 二进制运转换
    Python初学者第三天 运算符、while循环
    Python初学者第二天 用户输入和注释
    Python初学者第一天 Python安装及第一个Python程序
  • 原文地址:https://www.cnblogs.com/hust-ghtao/p/4380306.html
Copyright © 2011-2022 走看看