
在嵌入式系统中,RAM 的大小是非常有限的。尤其是做器件选型时,更小 RAM 的芯片意味着更低的采购价格,产品才会更具竞争力,有更高的毛利。
在这样极致的压榨下,留给堆栈的空间更加少了。开发者不得不面对爆栈的巨大风险。每个软件工程师都想有一个工具能够帮助他们检验栈的使用情况,从而很好的评估风险。
人们寻常采用的方法是把栈里都先写满一个特定的值,比如 0xAA。随后在程序运行一段时间之后看看还剩多少 0xAA 没有被改掉。这种方法确实有一定的效果,但是显然还不够直观,又比较麻烦。尤其是当工程有不止一个栈的时候。
为此,新版本的 gcc 编译器提供了一个有用的编译选项-fstack-usage。使用这个选项后,编译器会额外产生有关栈使用情况的信息,而 MCUXpresso 可以整理这些信息,并将它们非常清晰地显示出来。
fstack-usage与Call Graph
它以每个函数为基础,使编译器生成程序的堆栈使用信息。信息存放在后缀名为.su 的文件中。
下图是编译文件夹的内容,可以看到有一个同名的 su 文件。



前面带“>”的函数名称显示“根”函数:它们不能被从其他任何地方调用的。其中ResetISR就是 reset 入 口 函 数 , 而 exception handlers 里 面 都 是 中 断 服 务 程 序 。
HAL_UartReceiveBlocking()函数因为没有其它函数显式的调用它,所以也被认为是根函数。
这里我们可以看到这种分析的一个弱点,如果函数是通过函数指针的方式来调用那么该功能就无能为例了。但是使用者可以自己分析程序给续上。如果函数是递归的,则用一个特殊的双箭头标记。成本估算将针对单级递归。 Full Cost 表示累积堆栈使用量(此函数加上所有被调用的)。 Local Cost 表示本层的堆栈使用量。 Depth 表示由该函数引起的调用级别数。
此外,如果函数是用汇编语言写的,那么工具是无法统计它们的栈使用情况, 一律会统计成‘4’。但如果调用到了其它函数,深度和 Full cost 还是会被统计的。
需要注意这个堆栈使用报告仅涵盖每个函数或调用树的堆栈使用情况。它们不包括异常处理程序所需的额外堆栈空间。所以最后的堆栈计算是 ResetISR 栈+中断栈,如果允许中断嵌套,那么整个中断嵌套最长的情况必须要被考虑。

其它同栈保护有关的编译选项
- Wstack-usage
这是一个有用处的编译选项:-Wstack-usage。它能够在堆栈使用超过限制时产生 warning
信息。用法是:
-Wstack-usage=256
它表示如果栈使用量超过 256 时产生警告。这样就能更快速地知道哪个函数超了。只说它有些用处而不是非常有用是因为,只针对单个函数的堆栈用量, 不会按调用树累计被调用函数的堆栈总数。
- fstack-protector

小结
恩智浦MCU加油站
这是由恩智浦官方运营的公众号,着重为您推荐恩智浦MCU的产品信息、开发技巧、教程文档、培训课程等内容。

长按二维码,关注我们
END
更多恩智浦AI-IoT市场和产品信息,邀您同时关注“NXP客栈”微信公众号

NXP客栈
恩智浦致力于打造安全的连接和基础设施解决方案,为智慧生活保驾护航。
长按二维码,关注我们
暂无评论哦,快来评论一下吧!
