导读:在C语言的世界里,栈的地位非常举足轻重,许多错误都可能和栈设置有关,那么该如何确定栈的大小?
今天分享一点栈知识,帮助你确定栈的大小,参考链接请点击下方的阅读原文。
其实很多编译工具是可以获取函数调用信息的,比如:
KEIL 平台
可以使用参数:
-
--callgraph:生成一个静态调用图(html或文本格式),显示堆栈使用情况
-
--info=stack:列出所有全局符号的堆栈使用情况
以上两个参数分别生成Objects目录下的 xxx.htm文件(事实上这个--callgraph是默认参数,用浏览器打开这个文件即可)和 Listings目录下的xxx.map 文件(keil或者记事本打开)。
xxx.htm
xxx.map
事实上这个文件生成也是由默认参数 --map 管理的,不同的是增加 --info=stack 参数后,文件中还会增加如下信息:
它描述了每一个函数调用情况,并且把最大调用链和最大使用栈给你找出来了(这个文件打开有一个小技巧,双击 Target 1,即可打开这个文件,方便快捷)。
事实上,这些信息只能用于参考,而不能作为最终的栈大小,计算实际栈大小远比这个复杂,这个原文进行了深入阐述。
事实上,一般设置栈大小都不会采用如此复杂的计算,而是通过长时间运行来简单确定栈大小(一般 RTOS 都有栈检查功能函数),并且会在长时间运行获取栈大小的前提下预留一定大小的栈空间,这样一般来说都能保证有足够的栈空间。
IAR 平台
这个平台鱼鹰不是很熟悉,原文是这样写的:
IAR Embedded Workbench for Arm (EWARM) provides stack size report in the linker map file. To enable this, the following project settings are required:
-
Enable linker map file generation in Linker settings (List tap)
-
Enable stack usage analysis (Advanced tap).
谷歌浏览器自动翻译结果是:
用这个开发平台的道友可以试试。
GCC
使用参数:
-fstack-usage
并且 gcc上提供了堆栈保护功能,使用以下选项
-
-fstack-protector:在堆栈帧上为每个易受攻击的函数插入一个保护变量。
-
-fstack-protector-all:在堆栈帧上为所有函数插入一个保护变量。
然后在看看文中的几个有意思的点:
01 栈布局
一般情况下的栈布局有如下两种:
KEIL 平台下的属于第一种,这就是为什么栈空间小了会很大可能影响用户变量的原因(栈往低地址生长)。而 gcc 采用第二种情况,这种情况可以完全利用 RAM 空间,如果说这种布局还会导致栈空间不够,那么你怎么设置栈大小都没用了。
02 函数调用
需要特别了解来自开发工具的堆栈使用报告仅涵盖每个函数或调用树的堆栈使用情况。 它们不包括异常处理程序所需的额外堆栈空间。
假设应用程序仅对外设中断使用两个中断优先级,由于可能发生HardFault异常和NMI异常(如果应用程序使用),可能存在4级嵌套异常,如图所示。
(原作者为Joseph Yi)
这就是为什么栈计算复杂的原因了。
栈计算可用以下流程图:
(原作者为Joseph Yi)
03 栈大小难以计算原因
软件开发人员可能会发现,在许多情况下,报告无法提供有关应用程序某些部分的堆栈要求的信息。堆栈使用情况报告生成对某些代码不起作用的原因有很多:
-
在应用程序中使用函数指针可能意味着该工具无法生成调用树。
-
在许多工具中,C运行时库中函数的堆栈使用是未知的。
-
该应用程序包含递归函数调用或自修改代码。
在这些情况下,您可能必须手动计算这些函数的最大堆栈使用量,或者通过试验来估计这些函数。例如,您可以在运行程序之前使用调试器以某种数据模式填充堆栈内存空间,然后执行代码,并检查堆栈内存空间以查看程序执行已修改了多少堆栈空间。
也可以通过在项目中添加检测代码来处理堆栈估算。例如,附录I显示了gcc Arm Embedded(使用NewLib)的堆栈检查实用程序代码。
最后再说一点,鱼鹰知道 PID 系列文章很多道友都不是很感兴趣(从阅读量可以看出),但是鱼鹰还是会继续更新下去的,因为鱼鹰写这部分笔记的初衷本来就是给自己看的,所以不会因为你们不感兴趣而停止更新。
另外鱼鹰还想说的就是,一旦 PID 系列文章更新完毕,鱼鹰可能将停止更新。
为什么呢,从去年 11 月份开始到,因为做公众号而花费了很大精力,但收获很小,而且最近的状态是总想着怎么写出一篇好的文章,而不是说怎么研究技术问题。而本公众号的文章里面,只有 KEIL 调试系列和少数几篇文章还算满意,其他文章的价值很少。在鱼鹰看来,先有好的技术积累,才会有好的文章出现。最近一段时间一直在输出,而输入很少,所以鱼鹰准备暂停更新,直到认为有足够的技术积累再继续更新。
那什么时候恢复更新呢?鱼鹰无法确定,所以说如果你觉得本公众号没有价值了,那么可以取消关注。但是鱼鹰想说的是,当公众号恢复更新时,将呈现三大系列文章:
1、USB (包括如何自制一个调试器,将以它作为这个系列的最终目标)
2、FAT32FS 文件系统(源码理解,图解文件系统)
3、uCOS II (鱼鹰已全部看完并理解源码,只是需要点时间写出相应的笔记)
最近鱼鹰也算处于一种转型状态了,从单片机开发转向 linux 开发,不懂的知识点太多了,祝我好运咯!