就C语言而言,尝试分配不适合内存的局部变量或全局变量具有未定义的行为,这意味着任何事情都可能发生。
在实践中,取决于您的工具链,您的MMU / MPU设置(如果有)以及确切的内存布局,其结果可能是,在为堆栈保留的内存区域之外进行写操作会覆盖内存中包含的任何位置,从而导致“有趣”的结果,或某种与存储器相关的故障。您绝对不希望覆盖其他内存,并且很难从中恢复内存故障,因此,请确保不会发生这种情况。
主要的嵌入式工具链提供了一种计算程序的最大堆栈使用率的方法。更准确地说,它们计算的是最坏情况下的近似值,对于通常在小型嵌入式系统上运行的程序而言,这种近似值通常已足够好。仅当程序不使用动态功能(例如函数指针,递归,可变长度数组和alloca
)时,此方法才有效。
例如,使用GCC,编译器可以告诉您每个函数的堆栈使用情况,并结合控制流程图可以确定程序的堆栈使用情况上限。参见How to determine maximum stack usage in embedded system with gcc?
另请参阅Stack Size Estimation,其中提到了一些与编译器分开工作的工具。
请记住,除了main
外,还要考虑中断例程。
如果将变量设为永久变量(静态存储持续时间),即,它是带有static
限定符的全局变量还是局部变量,则链接程序应告诉您是否用完了BSS。它更加简单明了,但是您会失去在部分程序(例如引导过程)中将该内存用于其他用途的能力。您可以通过将全局变量设置为union
来重新获得某些功能,但这很危险,因为编译器无法保护您避免在错误的时间使用错误的联合成员。
,
gcc提供了标志-fstack-usage
和-Wstack-usage
,它们将输出每个函数的堆栈使用情况并警告过多的使用情况,这可以作为寻找有栈溢出风险的函数的起点。但是,如果函数调用深度会在许多小块中使堆栈溢出,将无法为您提供帮助。
一种可能的方法是计算硬件上堆栈末端的地址,以便您可以使用调试宏来告诉您剩余多少堆栈。当然,在问题发生之后,您将无法关闭大门-如果您有一个需要使用大量堆栈的函数,则需要在调用该函数之前进行堆栈检查;不是在函数的开始(通常是在函数入口使用栈,而不是在执行到达大缓冲区的声明时消耗栈)。
理想情况下,您应该以一种已知所有可能的代码路径的方式来设计代码,并且可以绕开它。 clang能够生成一个调用图,显示调用彼此的所有函数-如果您的代码很烂,那么看起来就像猫被塞进了羊毛筐,但是如果没有,那么您可以将堆栈使用情况与每个函数关联并进行工作列出任何代码路径的理论最大可能堆栈使用量。
可能有些商业工具会自动执行所有这些操作,尽管IDK是什么。
,
这个问题有点困惑,因为您永远不要在堆栈上分配大数组,尤其是在嵌入式系统中。如果您在20kib系统上声明一个大小为30kb的本地数组,则您将在运行时简单地用堆栈溢出杀死堆栈。
尽管有一些工具链提供了衡量堆栈使用情况的方法,但是有些程序员会给出有意义的错误,例如堆栈溢出时的软件中断/异常,您只能通过程序员的知识和代码审查来保护自己免受堆栈溢出的侵害。还有一种手动的方法可以通过调试器测试堆栈的使用情况,方法是使用一些废话值(例如0xAA)填充整个堆栈,然后以最大的代码覆盖率执行程序,然后分析内存映射以查看堆栈中还有多远找到0xAA。
但是,如果动态地声明数组,那么如何判断系统是否内存不足
通过检查malloc
的结果。但这对您来说不是问题,因为您永远不要在20kib裸机系统上使用动态内存。 Because it doesn't make any sense to do so。
应该要做的是通过将其设置为static
和/或将其移至文件范围来声明具有静态存储持续时间的数组。在这种情况下,如果使用过多的内存,则会出现链接器错误。链接器将发出“ .bss
部分的内存不足”或类似的消息。
本文链接:https://www.f2er.com/3062238.html