Check stack usage during run-time

28-May-2025

If you need to do run-time stack checking, you will have to implement this yourself.

A simple way to check the linker calculation result versus the actual stack usage during run-time is filling the stack area with a specific pattern (like 0xA5A5A5A5 checker/chessboard pattern) and then running the application. During run-time, the stack area patterns can be checked for actual usage as the objects on the stack will overwrite the fill pattern. The checking function can be used as instrumentation of the application code, wherever necessary. Alternatively, the memory content of the user stack area can be checked using the debugger and some strategically set breakpoints. This memory watch in the debugger will eliminate the use of a stack checking function.


Possible solution

The simplest and most straightforward way is to define a user function as cinit(). This user-defined function could also be added to cstart.c before main() but after variable initialization in cinit()

Here is a simple example using a user-defined fill loop, using a simple hello world project:

/*stack_fill.c*/
/* Fill the user stack with a pattern*/

extern unsigned int _lc_gb_MY_FILLED_STACK;    /* begin of group */
extern unsigned int _lc_ge_MY_FILLED_STACK;    /* end of group */

#pragma optimize 0                             /* no optimization for demonstration purpose */

volatile unsigned char *stackptr;              /* write char one location by one location */
volatile unsigned int *user_stack_start;
volatile unsigned int *user_stack_end;

void stack_fill(void)
{
   user_stack_start = &_lc_gb_MY_FILLED_STACK;    
   user_stack_end = &_lc_ge_MY_FILLED_STACK;
   for(stackptr = user_stack_start; stackptr < user_stack_end; stackptr++)
   {
      *stackptr = 0xA5;                       /* note the char writing mov.b */
   }
}
#pragma endoptimize
/*hello.c*/
#include <stdio.h>
void stack_fill(void);
int main(void)
{
   stack_fill();
   printf( "Hello world\n" );
}
/*hello.lsl*/
section_layout mpe:tc0:linear
{
    group MY_FILLED_STACK (ordered, contiguous, run_addr=mem:mpe:dspr0)
    {
      select "ustack_tc0";
    }
}


This will fill tc0 (core 0) or better absolute address of ustack for tc0.

If you examine the stack pointer A10 immediately after entry to main, before calling stack_fill(), A10 will be uninitialized and points to the top of the stack.
Stepping through, one can see the memory for the stack being filled from lowest to highest address in the memory watch.
After running printf(), go to the top of the stack memory (the highest address), and you will see the pattern broken with some entries.

You can download the example projects
TC23X_Stack_Check_v63r1, and TC27XD_Stack_Check_v63r1.


More resources

Was this answer helpful?