目录
前言
程序运行过程中,函数内部的局部变量或传参会放入 stack 中;内核架构文档中一般会定义使用哪个通用地址寄存器作为 stack pointer,编译器按照此要求实施 stack memory 寻址;以TC1.6.2 core 为例来说明 stack 管理的机制,其他内核与之类似;
1. TC1.6.2 core stack 管理相关寄存器
TC1.6.2 core 内核架构文档中定义了使用通用地址寄存器A[10] 作为 stack pointer;
另外,为了提高数据访问的安全性,TC1.6.2 core 支持中断使用单独的 stack pointer;ISP 为中断stack pointer 寄存器;
PSW.IS 位域控制ISP是否使用,
PSW.IS = 0 时,使用ISP 指向的stack 区域,中断发生时,硬件会先将ISP 的值加载到 stack pinter,然后再执行中断服务程序;
PSW.IS = 1 时,中断服务函数和其他所有函数一样,使用相同的stack memory, A[10]指向区域;
MCU RESET 后,PSW.IS 值为0,默认情况下,中断服务函数使用自己单独的stack;
2. stack 管理时用户代码需提供的支持
用户需要在 link 文件中为通用stack, 中断 stack 保留一定的memory 空间;至于 stack 所使用memory 空间的大小,和程序内部局部变量或传参的大小有关,正向评估不方便时,可以先给stack 分配一块较大的memory 空间,后面根据实际运行情况进行调整;
为stack 分配好存储空间后,要在初始化代码中,对中断相关的寄存器进行初始化(一般在启动代码中完成),根据 link 文件中,分配给 stack 的地址,为A[10],ISP 赋入正确的值,PSW.IS 可根据实际使用情况赋初值;
stack 生长的方向可以由高地址向低地址,或相反;一个往下生长的 stack 如下:
实际程序运行过程中,stack pointer(A[10]) 和 interrupt stack pointer(ISP) 都是可以动态调整的,这就为OS 的 stack 管理提供了方便,用户可以为每个 task 和 interrupt 分配不同大小的stack,在OS 进行任务切换,或程序进入中断ISR后,切换 stack pointer 指向用户定义stack memory;以对不同task 和interrupt stack memory进行隔离,提高数据访问的安全性;
3. stack 使用空间的评估
OS 为不同task 和 interrupt 提供了不同的 stack memory,并管理 task 切换,中断ISR 执行时 stack pointer 的切换;
OS 一般提供有 stack 使用情况检测的服务;其实现的基本原理可以是:初始化时给stack memory 初始化为一个用户定义的无效值(比如0xCC); 然后在每个task 或中断 ISR 退出时,检测其stack的使用情况,判断 stack memory 中有多少空间仍为定义的初始值,表示其并未使用,从而得到 task 或 interrupt 使用 stack 的大小;进行评估时,要保证测试case 的代码覆盖率,使task的所有代码得到充分执行;
4. stack 的溢出
stack 的溢出分 overflow 和 underflow;
overflow 是指在往stack 存临时变量的时候,stack memory 的空间 小于 存放临时变量所需的空间,导致临时变量存放到了 stack memory 外的地址空间;
例如上图中,临时变量继续往下放,放到了地址0xFF对应的memory 空间;
而 stack 外的memory 空间有可能被其他代码使用,这样相当于这部分代码使用的变量被篡改了,就有可能造成程序行为异常;
OS 一般提供 stack overflow 的检测,其实现的机制和OS stack 使用情况评估的方法类似,初始化时给stack memory 赋一个初值,然后运行过程中检测 stack bottom 的值是否被临时变量赋的值覆盖,如果没有,表示 stack 没有 overflow,反之表示 stack overflow;
stack underflow 是指临时变量存入了 stack top 外的空间;
例如上图中,临时变量存到了地址 0x201 对应的memory 空间;
下面的情况可能造成 stack underflow;一个函数的传参为 512 个元素 uint8 类型的数组,而函数中用 memcopy 函数给这个传参赋值,但调用 memcopy 函数时设置的数据copy 长度大于512,此种情况可能造成 stack underflow;
将task 和interrupt 的 stack memory 分配在一块连续的存储空间,这样可以用OS 中相邻 task stack overflow 的检测来变相检测当前 task stack 的underflow 事件;
程序流跳转时伴随着上下文现场信息切换及 stack 的使用及释放;上下文切换机制可参考: