【发布时间】:2021-03-01 19:48:48
【问题描述】:
我们公司购买了一个专有的C函数:我们有一个编译库ProcessData.a和一个接口文件来调用它:
# ProcessData.h
void ProcessData(char* pointer_to_data, int data_len);
我们想在ARM 嵌入式 CPU 上使用这个函数,并且我们想知道它可能使用多少堆栈空间。
问题:如何测量任意函数的堆栈使用率?
到目前为止,我尝试的是实现以下辅助函数:
static int* stackPointerBeforeCall;
void StartStackMeasurement(void) {
asm ("mov %0, sp" : "=r"(stackPointerBeforeCall));
// For some reason I can't overwrite values immediately below the
// stack pointer. I suspect a return address is placed there.
static int* pointer;
pointer = stackPointerBeforeCall - 4;
// Filling all unused stack space with a fixed constant
while (pointer != &_sstack) {
*pointer = 0xEEEEEEEE;
pointer--;
}
*pointer = 0xEEEEEEEE;
}
void FinishStackMeasurement(void) {
int* lastUnusedAddress = &_sstack;
while (*lastUnusedAddress == 0xEEEEEEEE) {
lastUnusedAddress++;
}
// Printing how many stack bytes a function has used
printf("STACK: %d\n", (stackPointerBeforeCall-lastUnusedAddress)*sizeof(int));
}
然后在函数调用前后使用它们:
StartStackMeasurement();
ProcessData(array, sizeof(array));
FinishStackMeasurement();
但这似乎是一个危险的 hack - 尤其是我从 stackPointerBeforeCall 中减去 4 并覆盖下面所有内容的部分。有没有更好的办法?
【问题讨论】:
-
没有好的方法可以做到这一点,但可能有一种不那么老套的方法。您运行此代码的嵌入式环境是否具有内存保护?它有线程吗?它是否具有(已弃用但不可替代的)POSIX 函数
getcontext、makecontext、setcontext和swapcontext? -
用模式填充堆栈然后检查它是堆栈检查的正常方法。如果堆栈指针始终指向最后压入的值,则减 4 对于 32 位系统是正确的。 (我没有检查 ARM 的文档。)在不了解您的操作系统和/或可用库的详细信息的情况下,我们不知道您的系统上是否有任何特殊的堆栈检查机制。如果堆栈使用取决于数据,您可能必须使用不同的输入数据执行测试。考虑向库的创建者询问最大堆栈使用量。
-
正确的做法是询问供应商。
-
一种非常 hacky 的方法是通过汇编程序读取 sp,使用已知的十六进制序列、0xAA 等从 sp 到堆栈末尾的所有内容。然后检查函数改变了多少0xAA。不是一门精确的科学,而是用于确定裸机系统中的峰值堆栈使用的一个很好的老技巧。
-
顺便说一句,发布的代码需要确保
pointer没有在堆栈上分配,否则它可能会决定销毁自己并将内容替换为地址 0xEEEEEEEE :) 最好的解决方法是static int* pointer; pointer = stackPointerBeforeCall - 4;
标签: c assembly arm callstack stack-size