Stack在函数调用、中断(异常)、RTOS中的应用

在计算机程序中,分支[Branch]具有很重要的意义。函数调用、中断产生时程序的跳转、OS中的Multiple Task的切换等等这些均属于分支范畴,说的直白点就是根据需求合理的控制执行流。执行这些跳转共有一个特征:还需要再返回到跳转前的Point。怎么记录需要返回到哪里?多层级的调用和返回都是有顺序的,怎么保证这些顺序?跳转前如有执行的环境怎么原封不动地保存?这样返回时才能继续之前的工作。程序执行的环境或者说执行流从CPU层次来看主要包括哪些核心内容?本篇文章重点介绍这些内容。

何为Stack?

Stack是这样一种结构:本身是一段连续的内存空间,那怎么使用这样一种内存空间才算是起到了栈的实际作用呐?首先要规定这一段连续空间的基地址,然后就从这个基地址开始依次放东西。取东西时也是从最上面的开始取。Stack这个英文含义就是把东西堆叠起来的意思。就像水桶盛水一样,进水的时候是从低往上,放水的时候是从上往低。存取有一定的先后顺序. 按照上面的方案管理这一段存储空间,就是发挥了栈的作用。因为栈使用的频率实在是太高了,所以在计算机汇编层次就有专门操作栈的指令。包括Push(入栈)、Pop(出栈)等。

其实栈又有一些逻辑上的分类:

根据先腾出空间再用还是先用再腾空间分为:

  1. 满堆栈:即入栈后堆栈指针sp指向最后一个入栈的元素。也就是sp先减一(加一)再入栈。

  2. 空堆栈:即入栈后堆栈指针指向最后一个入栈元素的下一个元素。也就是先入栈sp再减一(或加一)。

根据从高地址开始用还是从低地址开始用分为:

  1. 递增堆栈:即堆栈一开始的地址是低地址,向高地址开始递增。就如同一个水杯(假设上面地址大)开口的是大地址,从杯底开始装水。自己画一画图就清楚了。我就偷懒一下不画了。

  2. 递减堆栈:即堆栈一开始的地址是高地址,向低地址开始递增。就如同还是刚才说的那个水杯,现在开口的是小地址,从大地址开始用,往下走,相当于杯子口朝下。我们用的时候是把水往上一点点压上去。呵呵呵,不过这样的杯子就失去了用途。但在内存上还是可以的。

那么根据这上面分类方法,我们就可以得到四种栈的类型。

Cortex-M3中使用的是递减满堆栈(full descending stack)。

Stack在函数调用时的应用

我们使用高级语言设计程序时,为了程序的简介性和易读性,使用合理的函数抽象和函数调用是比较常用的设计方法。在函数调用时,有两个核心的问题需要关注:指令流(PC)的控制、临时数据(FP)的保存和恢复。这个也好理解,数据结构里提到的程序=数据结构+算法也是一个意思,一个程序就有两个重要的内容:指令、数据。通俗地描述一下函数调用时需要考虑的问题,大家想一想,我们写c语言时用到函数调用,有时候还嵌套调用很多函数。还有有些函数还需要参数和返回值。怎么处理各个函数的参数和返回值,以及当每一个函数完成工作时该返回到那个地方。这些都是要解决的问题。当然最容易想到的也是必须做的是在进行调用跳转之前,把我这个函数现有的状态保存起来,保存什么那,调用函数返回后的下一条指令,还有我这个函数需要的哪些数据。还有就是保存这些信息到哪些地方哪?这些都是我们要解决的问题。还有就是你不光要保存这些信息,还要保存这些信息的顺序。因为函数调用本身有顺序,你像a调用b,b又接着调用c。在c执行完后要返回到b,b执行完再返回a。呵呵,有顺序。

我们一一想办法来解决,当然别人已经用栈的策略解决的很完美了,我们只是想一些更简洁的最容易想起来的但是不完善的方法,也正说明了人家的策略是多么的优秀。

关于调用函数的问题,我们可以把返回地址保存到一些地方,当然程序员知道在那?还知道顺序,再根据顺序返回就好了,但做这样的工作太累了,除了写程序还要记这些东西。这样太累了,聪明的程序员肯定也不这样做。关于传参,有这样可以考虑的,用专门规定好的寄存器来做传参。行,但有缺陷,如果传的参数很多或者是变化的,就不好用寄存器传参了。而且我们有操作系统时往往要求编译器产生的代码具有可重入性,也就是保证代码和数据的相对独立性。一个函数被调用两次,都有两次的参数环境。到底现在我们是怎么做的呐。答案是用栈。

其他废话不多说了,直接上个Cortex-M3的Demo。

function_stack.c :

int  add(int a,int b);
void test(void);


void  main_frame(void)
{
        int result = 11;
        result = add(1,2);

}



int  add(int a,int b)
{
        int result_temp = 22;

        result_temp = a + b;
        test();
        return result_temp;
}

void test(void)
{
        int a = 31,b = 32,c = 33;


}

function_stack.s :

        .cpu arm7tdmi
        .eabi_attribute 20, 1
        .eabi_attribute 21, 1
        .eabi_attribute 23, 3
        .eabi_attribute 24, 1
        .eabi_attribute 25, 1
        .eabi_attribute 26, 1</
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值