MSP430上运行的C程序需要的最大堆栈大小

10
在不使用递归的C程序中,理论上应该可以计算出调用给定函数及其所调用的任何函数所需的最大/最坏情况堆栈大小。是否有任何免费、开源的工具可以从源代码或编译后的ELF文件中实现这一点?
另外,是否有一种方法可以从ELF文件中提取函数的堆栈帧大小,以便我可以尝试手动计算?
我正在使用MSPGCC 3.2.3编译MSP430(我知道它是一个旧版本,但在这种情况下我必须使用它)。分配的堆栈空间在源代码中设置,并且应尽可能小,以便其余内存可以用于其他事情。我已经阅读到需要考虑中断使用的堆栈空间,但我使用的系统已经考虑了这一点 - 我试图计算需要额外添加多少空间。此外,我已经阅读到函数指针使这个问题变得困难。在这里仅有几个地方使用函数指针,我知道它们可以调用哪些函数,因此如果已知被调用函数和调用函数所需的堆栈空间,则可以手动考虑这些情况。
静态分析似乎比运行时堆栈绘制更加健壮,但如果没有好的静态方法,那么在运行时计算是一种选择。
编辑:
我发现GCC的-fstack-usage标志,它将编译每个函数的帧大小保存下来。不幸的是,MSPGCC不支持它。但对于任何试图在不同平台上进行类似操作的人来说,这可能会很有用。

这真的是解决问题的方法吗?我一直对堆栈非常慷慨,并使用堆栈金丝雀进行保护,以确保其完整性。我认为这种方法的主要问题在于它可能会在以后引起麻烦。比如当你需要使用24位PC而不是16位(现在只是一般的8位经验)去获取更大的程序内存时,或者你只需要一些额外的功能最好通过一些额外的调用层来实现。那么一个精确设置的堆栈可能真的会让你后悔。当然,如果你正在挤出最后一点空间,那就没问题了,但我认为这真的应该是最后的选择。 - Jubatian
有没有任何免费的开源工具可以做到这一点?IAR IDE 有一个免费版本(不是开源),可以使用30天或4K代码限制。其中,链接器清单选项会生成应用程序的堆栈使用情况。即使您正在使用GCC,为了获取详细信息,例如堆栈大小(总体和每个函数)、代码大小(总体和每个函数)以及其他详细信息,如内存布局和变量地址和大小等,您也可以使用IAR嵌入式工作台。 - Harikrishnan
可能是在编译时检查堆栈使用情况的重复问题。 - shodanex
5个回答

2
虽然静态分析是确定最大堆栈使用量的最佳方法,但您可能需要采用实验方法。这种方法不能保证您获得绝对的最大值,但可以为您提供有关堆栈使用情况的非常好的想法。
您可以检查链接器脚本以获取 __STACK_END 和 __STACK_SIZE 的位置。您可以使用这些来填充堆栈空间,例如 0xDEAD 或 0xAA55 这样容易识别的模式。通过折磨测试运行代码,尽可能多地生成中断。
测试后,您可以检查堆栈空间,以查看堆栈被覆盖了多少。

你甚至可以将它们声明为extern。extern char __STACK_END; &__STACK_END 将是堆栈中最后一个字节的地址。 - Michael

0

0

有趣的问题。

我希望这些信息在调试版本中包含的调试数据中是静态可用的。

我简要查看了DWARF标准,它确实指定了两个函数属性DW_AT_frame_baseDW_AT_static_link,可以用于“计算紧密包围子程序或入口点的相关实例的框架基础”。


谢谢。我不确定那些有多有用,但我在DWARF规范中找到了“调用帧信息”,它看起来可能有更多信息。现在我只需要让GCC生成.debug_frame部分——-gdwarf-2 -g3不能做到这一点。 - cjc

0
我认为唯一的方法是通过静态分析。您需要考虑所有非静态本地变量的空间,这些变量大多是指针,但指针将在堆栈中存储,您还需要为调用者内当前运行地址保留空间,因为编译器将其存储在堆栈上,以便在函数返回后将控制返回给调用者,此外,您还需要为所有函数参数预留空间。
基于此,如果您有一个能够计算所有参数、自动变量并确定它们大小的工具,您应该能够计算出所需的最小堆栈帧大小。
请注意,编译器也可能尝试在堆栈上对齐值,这可能会使堆栈空间要求比您从此计算中预期的要大一些。

0

某些嵌入式IDE可以在运行时提供堆栈使用信息,我知道IAR嵌入式工作台支持此功能。

请注意,您需要考虑中断异步发生的情况,因此要考虑最大堆栈使用场景并添加中断上下文。如果像ARM处理器那样支持嵌套中断,则还需要考虑这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接