7.8 Stack Usage Guidance
MPLAB XC-DSC, 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
xc-dsc-ld
or xc-dsc-gcc
interface. The MPLAB X IDE
Project Properties window provides a convenient check box to
enable to this feature under the category XC-DSC
> Analysis Tools.
When this feature is enabled, MPLAB XC-DSC will provide some additional information pertaining to the linked executable to the terminal or build-output window of MPLAB X IDE. 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 XC-DSC 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 XC-DSC 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 XC-DSC 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 XC-DSC 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 11.2.3.2 The C Stack Usage section. A minimum stack size can be enforced using the features described in the 11.2.3.1 Software Stack section.