c代码在main开始后用模式(比如0xABABABAB)绘制嵌入堆栈



我正在使用堆栈绘制/足迹分析方法进行动态内存分析。

使用足迹分析动态确定堆叠深度

基本上,这个想法是在应用程序开始执行之前,用一个专用的填充值填充分配给堆栈区域的全部内存,例如0xABABABAB。每当执行停止时,可以从堆栈的末尾向上搜索堆栈内存,直到找到一个不是0xABABABB的值,该值被认为是堆栈已使用的程度。如果找不到专用值,则表示堆栈已占用所有堆栈空间,很可能已溢出。

我想要一个c代码来用一个模式从上到下填充堆栈。

void FillSystemStack()
{
extern char __stack_start,_Stack_bottom;

}

注意

  • 我使用的是eclipse上用QEMU模拟的STM32F407VG板
  • 堆栈从较高地址增长到较低地址
  • 堆栈的起始值为0x20020000
  • 堆栈的底部是Ox2001fc00

您不应该在main()开始后完全填充堆栈,因为一旦main()开始,堆栈就在使用中。完全填充堆栈将覆盖已使用的堆栈位,并可能导致未定义的行为。我想您可以在main()开始后不久填充堆栈的部分,只要您注意不要覆盖已经使用的部分。

但更好的方案是在调用main((之前用模式填充堆栈。查看工具链的启动代码。启动代码在调用main()之前初始化变量值并设置堆栈指针。启动代码可能在程序集中,具体取决于您的工具链。初始化变量的代码可能是一个简单的循环,它将字节或字从适当的ROM复制到RAM部分。您可能可以使用此代码作为示例来编写一个新的循环,该循环将使用模式填充堆栈内存范围。

这是一个Cortex M,所以它可以重置堆栈指针。这意味着它几乎可以立即为C代码做好准备。如果重置向量是用C编写的,并执行堆叠/C函数调用,那么在很早的阶段填充堆栈就太晚了。这意味着您不应该从应用程序C代码中执行此操作。

实现您所描述的技巧的正常方法是通过电路内调试器。下载程序,点击重置,在调试器的帮助下填充堆栈。将有一些方便的调试器命令可用于执行此操作。执行程序,尽可能多地使用它,观察调试器内存映射中的堆栈。

根据@kkrambo答案的见解,我试图在main开始后绘制堆栈,注意不要覆盖已经使用的部分。我的堆叠油漆和堆叠计数功能如下所示:

StackPaint

uint32_t sp;
#define STACK_CANARY 0xc5
#define WaterMark 0xc9
void StackPaint(void)
{
char *p = &__StackLimit; // __StackLimit macro defined in linker script

sp=__get_MSP();
PRINTF("stack pointer %08x rnn",sp); 
while((uint32_t)p < sp)
{
if(p==&__StackTop){ // __StackTop macro defined in linker script
*p = WaterMark;
p++;
}
*p = STACK_CANARY;
p++;
}
}

堆叠计数

uint16_t StackCount(void)
{
PRINTF("In the check address function in main file rnn");
const char *p = &__StackLimit;
uint16_t       c = 0;
while(*p == WaterMark || (*p == STACK_CANARY && p <= &__StackTop))
{
p++;
c++;

}

PRINTF("stack used:%d bytes n",1024-c);
PRINTF("remaining stack :%d bytesn",c);

return c;
}

相关内容

最新更新