8.8 Stack Usage Guidance
MPLAB XC16, in common with other Microchip MPLAB XC compiler offerings, provides a feature we are calling 'Stack Usage Guidance'. This is a compile-time static analysis of the executable meant to guide the user to an appropriate worst-case stack usage requirement. As will be seen, this guidance may need to be tempered with other facts that cannot be determined by a static analysis.
Usage
This feature requires a 'PRO' license and is enabled by adding
-mchp-stack-usage
to the normal link line, either through the
xc16-ld
or xc16-gcc
interface. The MPLAB X IDE
Project Properties window provides a convenient check box to enable to this feature
under the category XC16>Analysis Tools.
When this feature is enabled, MPLAB XC16 will provide some additional information pertaining to the linked executable to the terminal or build-output window of MPLAB X. Additionally, if a 'map' file is being specified, the language tool will emit more detailed information to the Map file for a permanent record.
Operation
When enabled, MPLAB XC16 will analyze the complete executable and attempt to provide the amount of stack at the deepest point in memory. Again, this is a static analysis and may be limited by the information that is available at compile-time. During analysis, the tool may discover that a complete picture of the stack usage cannot be made. If this is the case, additional information will be displayed on the output terminal. This information will also be recorded in the Map file, if specified.
The following items may trigger a partial result to be made: recursion; explicit dynamic stack assignments or adjustments; stack usage caused by interrupt functions; unconnected, or disjoint, functions or other executable code. By definition, these types of items are dynamic and therefore their stack usage cannot be determined via static analysis. More detail on these items follows.
The summary information is provided in the following form:
====================== STACK USAGE GUIDANCE ======================
In the call graph beginning at __reset(),
324 bytes of stack are required.
All MPLAB XC16 executables start at __reset;
so we provide stack
guidance starting from this point.
Recursion
Recursion occurs when the program directly or indirectly causes a loop where
there is a net adjustment of the stack usage. MPLAB XC16 does not limit this
identification across function boundaries; indeed (un)carefully constructed
assembly language programs could cause this error to be emitted even within a
function boundary. The most obvious example would be a traditional, recursive,
implementation of factorial. A more subtle version from the standard C library
is fflush()
- which, if given a NULL parameter, will call
fflush()
on all the currently open IO streams.
Any recursion that is detected will cause MPLAB XC16 to emit the following messages:
1. Recursion has been detected:
_function_name (address 0x8bc)
No stack usage predictions can be made.
Each function, where the recursion has been detected, will appear in the list. The output to the Map file will also contain the code address near where recursion has been detected.
Stack Adjustments
Any stack adjustments that cannot be determined at compile time will trigger a
message. This may be caused by assembly code writing a value explicitly to the
stack pointer (W15) or by a variable allocation using alloca()
.
In this case, we will emit the following diagnostic:
2. Indeterminate stack adjustment has been detected:
_function_name (address 0x286c)
No stack usage predictions can be made.
Each function where stack adjustment has been detected will appear in the list. The output to the Map file will also contain the code address near where adjustment has been detected.
Interrupt Functions
Every embedded application will have some interrupt functions. Unfortunately we cannot determine when these will occur during the run-time flow of the application. When interrupt functions are discovered, we will emit the following information:
3. The following labels are interrupt functions:
__T1Interrupt uses 18 bytes (address 0x2f8)
We cannot determine the stack impact of these events. Please adjust the guidance according to the application flow.
Each interrupt function will appear in the list. It will contain the amount of stack that is used by that interrupt including any functions that may be called. The code address of the interrupt handler will be emitted to the Map file.
The total amount of allocated stack should be increased by the total amount of stack that can be consumed by the largest interrupt flow; this would include any interrupts that may themselves be interrupted. Your application may limit which interrupts are themselves interruptible using various means. As the application developer, please adjust the stack usage based upon your knowledge of how the nested interrupt system will work in your application.
Unconnected Executable Code
Unconnected executable code cannot be reached by normal flow analysis. Perhaps this code represents functions that are never called, or functions that are called indirectly via function pointers. In any event, we cannot determine when or if these functions are actually called. When detected, the tool will emit the following messages:
4. The following labels cannot be connected to the main call graph.
This is usually caused by some indirection:
_function_name uses 10 bytes (address 0x598)
We cannot determine the stack impact of these events. Please adjust the guidance according to the application flow.
Each block of code that cannot be reached will be displayed along with the amount of stack consumed. The address of the code block will be presented only in the Map file. These may not be complete functions, though it is unlikely for C code.
Using the Guidance
The value given in the stack guidance only represents what the tool can see. It does not include any 'stack guard' setting that might be present. The default stack guard is 16-bytes, but this is configurable for each project. Adjust the guidance based upon the caveats that may be presented in the report. An explicit stack can be allocated using the features described in the The C Stack Usage section. A minimum stack size can be enforced using the features described in the Software Stack section.