如何测量 C 中任意函数调用使用的堆栈数量?
Posted
技术标签:
【中文标题】如何测量 C 中任意函数调用使用的堆栈数量?【英文标题】:How to measure the amount of stack an arbitrary function call uses in C? 【发布时间】: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;
【参考方案1】:
编译程序并分析相关函数的程序集或机器代码。许多函数以静态方式使用堆栈,而这种静态大小可以通过分析编译代码来推断。一些函数基于一些计算动态分配堆栈空间,通常与一些输入参数相关联。在这些情况下,您将看到用于分配堆栈空间的不同指令,并且必须回过头来推理如何得出动态堆栈大小。
当然,必须通过更新函数(库)来重新进行此分析。
【讨论】:
【参考方案2】:您可以使用getrusage,这是一个可以让您了解软件资源使用情况的函数,尤其是ru_isrss
,它是
一个整数值以同样的方式表示,即用于堆栈空间的非共享内存量
(source)
然后,您可以通过对库的模拟调用将其与程序的堆栈使用情况进行比较。
但是,这只有在您的系统实现了ru_isrss
(与 linux 不同)时才有效,否则该字段将设置为 0。
【讨论】:
以上是关于如何测量 C 中任意函数调用使用的堆栈数量?的主要内容,如果未能解决你的问题,请参考以下文章