4.6.1.23 Stack Option

The -mstack=model[:size|auto] option selects the stack model to be used by a program, which will dictate where the stack-based variables for functions that do not use a stack specifier will be allocated memory. Additionally, it can specify the size of memory reserved for the stacks.

Functions can use stack specifiers (described in 5.8.1.3 Reentrant And Nonreentrant Specifiers) to indicate which stack should be used for that function's stack-based variables. For functions that do not use these specifiers, the -mstack option controls the stack type that the compiler will use.

The two data stacks available are called a compiled stack and a software stack (described in 5.7.2 Data Stacks). The stack models that can be used with this option are described in the table below.

Table 4-13. Stack Suboptions
Model Default Allocation for Stack-based Variables
compiled or nonreentrant Use the compiled stack for all functions not using a stack specifier; these functions will then be non-reentrant.
software or reentrant Use the software stack for functions not using a stack specifier; these functions will then be reentrant.
hybrid Use the compiled stack for functions not using a stack specifier and that are not called reentrantly; use the software stack for all other functions not using a stack specifier; functions are only reentrant if required.

If the -mstack option is not used, all functions not using a stack specifier will use the compiled stack and be non-reentrant.

The software (or reentrant) or hybrid models have no effect on projects targeting baseline and mid-range devices, as these devices only support a compiled stack. In addition, all interrupt functions for any device must use the compiled stack, but functions they call may use the software stack.

The hybrid model (-mstack=hybrid) will let the compiler choose how to encode each function based on how it is called. A function is compiled to use the software stack if it is called reentrantly in the program; otherwise, it will use a compiled stack. This model allows for reentrancy, when required, but takes advantage of the efficiency of the compiled stack for the majority of the program’s functions.

Note: Use the software (reentrant) setting with caution. The maximum runtime size of the software stack is not accurately known at compile time, so the compiler cannot predict an overflow, which could corrupt objects or registers. When all functions are forced to use the software stack, the stack size might increase substantially. Code to access objects on a software stack is typically larger than that used to access objects on a compiled stack.

In addition to the stack model, this option can be used to specify the maximum size of memory reserved by the compiler for the software stack. This option configuration only affects the software stack; there are no controls for the size of the compiled stack, which is fixed and known at compile time.

Distinct software stacks are created for use by main-line code and interrupt functions, but this is transparent at the program level. In the case of PIC18 devices, separate stacks are created for high- and low-priority interrupts (along with one for main-line code), each interrupt stack available for all interrupt functions associated with an interrupt source set to that priority. So, for example, if you are using a PIC18 device with the vectored interrupt controller enabled, each reentrant interrupt function defined using the __high_priority keyword will use the software stack devoted to high-priority interrupts. The compiler automatically manages the allocation of memory to each stack. If your program does not define any interrupt functions, all the available memory can potentially be made available to the software stack used by main-line code.

The maximum space the compiler will attempt to reserve for each area of the stack can be specified by following the reentrant stack type with a colon-separated list of decimal values, each being the size, in bytes, of the memory to be reserved. The sizes specified in the option correspond in this order to: the main-line code, the low-priority interrupt and the high-priority interrupt. For example the option:
-mstack=reentrant:200:0:40
when used with PIC18 projects will attempt to reserve 200 bytes for the main-line stack, zero bytes for the low-priority interrupt stack, and 40 bytes for the high-priority interrupt stack. At runtime, the stacks will be able to grow to the specified sizes with no corruption of data. This memory is reserved unconditionally, even if no reentrant functions are present in the program.
Alternatively, any size argument may be specified as auto, in which case the compiler will calculate a maximum size for this stack after other static, stack, and heap allocations have been made. Memory with this calculated size will only be reserved, however, if the compiler detects the presence of any function using a reentrant stack. If no -mstack option is specified, then the compiler uses an auto setting for every stack that can be potentially used by the program. Whenever acting with an auto stack size setting, the compiler will issue a compiler advisory message if reentrant functions have been detected and memory has been reserved as a result. For PIC18 devices, the following example:
-mstack=reentrant:auto:30:50
will arrange the stack starting locations so that the low-priority interrupt stack can grow to at most 30 bytes (before overflow); the high-priority interrupt stack can grow to at most 50 bytes (before overflow); and the main-line code stack can consume the remainder of the free memory after other static, stack, and heap allocations have been made. If you are not using an interrupt, it is recommended that you explicitly set the unused interrupt stack size to zero using this option.

If the maximum stack sizes are specified with this option, each size must be a numerical value or the auto token; do not leave a size field empty. If the sizes specified in this option would allocate more stack memory than is available, a warning will be issued and only the available memory will be utilized.

The size of the heap used by dynamic memory allocation functions is also dynamic in nature, and memory must be reserved for its use. That memory is specified using the -mheap option (see 4.6.1.11 Heap Option). A size argument of auto can be used with both the -mstack and -mheap options, in which case the compiler will evenly distribute the free memory remaining between the heap and stacks after statically allocated objects have been placed.