5.4.2.2 Automatic Storage Duration Objects
Objects with automatic storage duration, such as auto, parameter objects, and temporary variables, are typically allocated space on a stack implemented by the compiler.
MPLAB XC8 has two stack implementations: a compiled stack and a software stack (described in Data Stacks). Objects nominated for space on the software stack might be allocated to dynamic working registers to improve efficiency; however, this does not alter the characteristic of the function. Each C function is compiled to use exactly one of these stacks for its automatic storage duration objects and the table below summarizes how the choice of stack affects a function’s reentrancy.
Data Stack Used | Function Model | Supported Device Families |
---|---|---|
Compiled stack | Non-reentrant | All devices |
Software stack, including working registers | Reentrant | Enhanced Mid-range and PIC18 devices |
When compiling for those devices that do not support the reentrant function model, all functions are encoded to use the compiled stack, which are non-reentrant functions. The use of dynamic working registers does not affect the reentrancy of the function.
For the Enhanced Mid-range and PIC18 devices, by default the compiler will
use the non-reentrant model for all functions. The -mstack
option (see
Stack Option) can be used to
change the compiler’s default behavior when assigning function models. Select the
reentrant
argument with this option so that the compiler will always
choose the reentrant model (software stack and/or working registers) for each function. Set
this option to hybrid
to allow the compiler to decide how each function
should be encoded, based on the following criteria.
- The function appears in multiple call graphs
- The function is recursive
- The function is a member of a group of buddy functions where more than one of the functions are active at the same time
- The function was referenced by assembly code
- The function has local optimizations applied
Alternatively you can change the function model for individual functions
by using function specifiers when you define the function. Use either the
__compiled
or __nonreentrant
specifier (identical
meanings) to indicate that the specified function must use the compiled stack, without
affecting any other function. Alternatively, use either the __software
or
__reentrant
specifier to indicate a function must be encoded to use the
software stack and/or working registers.
The function specifiers have precedence over the -mstack
option setting. If, for example, the option -mstack=compiled
has been
used, but one function uses the __software
(or
__reentrant
) specifier, then the specified function will use the
software stack and/or working registers and all the remaining functions will use the
compiled stack. These functions specifiers also override any choice made by the compiler in
hybrid mode.
If the -mstack=compiled
option has been issued or a
function has been specified as __compiled
(or
__nonreentrant
) and that function appears in more than one call graph
in the program, then a function duplication feature automatically comes into effect (see
Function Duplication). Duplicating
a non-reentrant function allows it to be called from multiple call graphs, but cannot allow
the function to be called recursively.
The auto objects defined in a function will not necessarily be allocated memory in the order declared, in contrast to parameters which are always allocated memory based on their lexical order. In fact, auto objects for one function can be allocated in many RAM banks.
The standard const
qualifier can be used with auto
objects and forces them to be read-only. These objects, however, might not be stored on the
stack. See Const Auto Objects for how
the compiler allocates such objects.