2.11.4. __user_initial_stackheap()
__user_initial_stackheap() returns the locations of the initial stack and heap.
In RVCT v2.x and earlier, the default implementation of __user_initial_stackheap() used the value of the symbol Image$$ZI$$Limit. This symbol is not defined if the linker uses a scatter‑loading description file (specified with the ‑‑scatter command‑line option) and so __user_initial_stackheap() must be re‑implemented if you are using scatter‑loading description files, otherwise your link step fails.
In RVCT v3.x, the library includes further implementations of __user_initial_stackheap(), and can select the correct one for you automatically from information given in a scatter‑loading description file. This means that it is not necessary to re‑implement this function if you are using scatter‑loading files. See Using a scatter‑loading description file for more information.
Note
If you re‑implement __user_initial_stackheap(), this overrides all library implementations. This enables existing applications to work without change.
__value_in_regs struct __initial_stackheap __user_initial_stackheap(unsigned R0, unsigned SP, unsigned R2);
__user_initial_stackheap() returns the:
heap base in r0
stack base in r1, that is, the highest address in the stack region
heap limit in r2
stack limit in r3, that is, the lowest address in the stack region.
If this function is re‑implemented, it must:
use no more than 88 bytes of stack
not corrupt registers other than r12 (ip)
maintain eight‑byte alignment of the heap.
For the default one‑region model, the values in r2 and r3 are ignored and all memory between r0 and r1 is available for the heap. For a two‑region model, the heap limit is set by r2 and the stack limit is set by r3.
The value of sp (r13) at the time __main() is called is passed as an argument in r1. The default implementation of __user_initial_stackheap(), using the semihosting SYS_HEAPINFO, is given by the library in module sys_stackheap.o.
To create a version of __user_initial_stackheap() that inherits sp from the execution environment and does not have a heap, set r0 and r2 to the value of r3 and return. See __user_setup_stackheap()) for more information.
The definition of __initial_stackheap in rt_misc.h is:
struct __initial_stackheap
{
unsigned heap_base, stack_base, heap_limit, stack_limit;
};
Note
The value of stack_base is 0x1 greater than the highest address used by the stack because a full‑descending stack is used.
The values returned in r0 to r3 depend on whether you are using the one‑ or two‑region memory model:
- One‑region
(r0,r1) is the single stack and heap region. r1 is greater than r0. r2 and r3 are ignored.
- Two‑region
(r0, r2) is the initial heap and (r3, r1) is the initial stack. r2 is greater than or equal to r0. r3 is less than r1.
Using a scatter‑loading description file
The default implementation of __user_initial_stackheap() uses the value of the symbol Image$$ZI$$Limit. This symbol is not defined if the linker uses a scatter‑loading description file. However, the C library provides alternative implementations that you can make use of through information in scatter‑loading description files.
Note
If you re‑implement __user_initial_stackheap(), this overrides all library implementations.
Selecting the one‑region model automatically
Define one special execution region in your scatter‑loading description file, ARM_LIB_STACKHEAP. This region has the EMPTY attribute.
This causes the library to select an implementation of __user_initial_stackheap() that uses this as the combined heap/stack region. This uses the value of the symbols Image$$ARM_LIB_STACKHEAP$$Base and Image$$ARM_LIB_STACKHEAP$$ZI$$Limit.
Selecting the two‑region model automatically
Define two special execution regions in your scatter‑loading description file, ARM_LIB_HEAP and ARM_LIB_STACK. Both regions have the EMPTY attribute.
This causes the library to select an implementation of __user_initial_stackheap() that uses the value of the symbols Image$$ARM_LIB_HEAP$$Base, Image$$ARM_LIB_HEAP$$ZI$$Limit, Image$$ARM_LIB_STACK$$Base, and Image$$ARM_LIB_STACK$$ZI$$Limit.
An example scatter‑loading description file to define both ARM_LIB_HEAP and ARM_LIB_STACK is shown in Example 2.23.
Example 2.23. ARM_LIB_HEAP and ARM_LIB_STACK scatter‑loading description
FLASH_LOAD 0x0000 0x00200000
{
VECTORS +0 0x400
{
* (:gdef:__vectab_stack_and_reset, +FIRST)
; Additional region for other vectors would be added here
}
;; Maximum of 256 exceptions (256*4bytes == 1024 == 0x400)
CODE 0x400 FIXED
{
* (+RO)
}
DATA 0x20000000 0x00200000
{
* (+RW, +ZI)
}
;; Heap starts at 1MB and grows upwards
ARM_LIB_HEAP 0x20100000 EMPTY 0x100000‑0x8000
{
}
;; Stack space starts at the end of the 2MB of RAM
;; And grows downwards for 32KB
ARM_LIB_STACK 0x20200000 EMPTY ‑0x8000
{
}
}
In Example 2.23, __vectab_stack_and_reset is a special library section that provides a convenient way for the initial values of sp and pc to be placed in the vector table starting at address 0 for Cortex‑M3 embedded applications. sp is initialized appropriately from either ARM_LIB_STACKHEAP (for the one‑region model) or ARM_LIB_STACK (for the two‑region model).
If you use a scatter file but do not specify any special region names and do not re‑implement __user_initial_stackheap(), the library generates an error message.