1.11.3 Stack pointer initialization and heap bounds

The C library requires you to specify where the stack pointer begins. If you intend to use ARM library functions that use the heap, for example, malloc(), calloc(), or if you define argc and argv command-line arguments for main(), the C library also requires you to specify which region of memory the heap is initially expected to use.

You must always specify where the stack pointer begins. The initial stack pointer must be aligned to a multiple of eight bytes.

You might have to configure the heap if, for example:

  • You intend to use ARM library functions that use the heap, for example, malloc(), calloc().
  • You define argc and argv command-line arguments for main()

If you are using the C library's initialization code, use any of the following methods to configure the stack and heap:

  • Use the symbols __initial_sp, __heap_base, and __heap_limit.
  • Use a scatter file to define ARM_LIB_STACKHEAP, ARM_LIB_STACK, or ARM_LIB_HEAP regions.
  • Implement __user_setup_stackheap() or __user_initial_stackheap().

Note:

The first two methods are the only methods that microlib supports for defining where the stack pointer starts and for defining the heap bounds.

If you are not using the C library's initialization code (see 1.7.1 Building an application without the C library), use the following method to configure the stack and heap:

  • Set up the stack pointer manually at your application's entry point.
  • Call _init_alloc() to set up an initial heap region, and implement __rt_heap_extend() if you need to add memory to it later.

Configuring the stack and heap with symbols

Define the symbol __initial_sp to point to the top of the stack.

If using the heap, also define symbols __heap_base and __heap_limit.

You can define these symbols in an assembly language file, or by using the embedded assembler in C.

For example:

__asm void dummy_function(void)
{
    EXPORT __initial_sp
    EXPORT __heap_base
    EXPORT __heap_limit
__initial_sp EQU STACK_BASE
__heap_base EQU HEAP_BASE
__heap_limit EQU (HEAP_BASE + HEAP_SIZE)
}

The constants STACK_BASE, HEAP_BASE and HEAP_SIZE can be defined in a header file, for example stack.h, as follows:

/* stack.h */
#define HEAP_BASE 0x20100000  /* Example memory addresses */
#define STACK_BASE 0x20200000
#define HEAP_SIZE ((STACK_BASE-HEAP_BASE)/2)
#define STACK_SIZE ((STACK_BASE-HEAP_BASE)/2)

Note:

This method of specifying the initial stack pointer and heap bounds is supported by both the standard C library (standardlib) and the micro C library (microlib).

Configuring the stack and heap with a scatter file

In a scatter file, either:

  • Define ARM_LIB_STACK and ARM_LIB_HEAP regions.

    If you do not intend to use the heap, only define an ARM_LIB_STACK region.

  • Define an ARM_LIB_STACKHEAP region.

    If you define an ARM_LIB_STACKHEAP region, the stack starts at the top of that region. The heap starts at the bottom.

Configuring the stack and heap with __user_setup_stackheap() or __user_initial_stackheap()

Implement __user_setup_stackheap() to set up the stack pointer and return the bounds of the initial heap region.

If you are using legacy code that uses __user_initial_stackheap(), and you do not want to replace __user_initial_stackheap() with __user_setup_stackheap(), continue to use __user_initial_stackheap().

Note:

ARM recommends that you switch to using __user_setup_stackheap() if you are still using __user_initial_stackheap(), unless your implementation of __user_initial_stackheap() is:
  • Specialized in some way such that it is complex enough to require its own temporary stack to run on before it has created the proper stack.
  • Has some user-specific special requirement that means it has to be implemented in C rather than in assembly language.

Configuring the heap from bare machine C using _init_alloc and __rt_heap_extend

If you are using a heap implementation from bare machine C (that is an application that does not define main() and does not initialize the C library) you must define the base and top of the heap as well as providing a heap extension function.

  1. Call _init_alloc(base, top) to define the base and top of the memory you want to manage as a heap.

    Note:

    The parameters of _init_alloc(base, top) must be eight-byte aligned.
  2. Define the function unsigned __rt_heap_extend(unsigned size, void **block) to handle calls to extend the heap when it becomes full.

Stack and heap collision detection

By default, if memory allocated for the heap is destined to overlap with memory that lies in close proximity with the stack, the potential collision of heap and stack is automatically detected and the requested heap allocation fails. If you do not require this automatic collision detection, you can save a small amount of code size by disabling it with #pragma import __use_two_region_memory.

Note:

The memory allocation functions (malloc(), realloc(), calloc(), posix_memalign()) attempt to detect allocations that collide with the current stack pointer. Such detection cannot be guaranteed to always be successful.

Although it is possible to automatically detect expansion of the heap into the stack, it is not possible to automatically detect expansion of the stack into heap memory.

For legacy purposes, it is possible for you to bypass all of these methods and behavior. You can do this by defining the following functions to perform your own stack and heap memory management:

  • __rt_stackheap_init()
  • __rt_heap_extend()

Extending heap size at runtime

To enable the heap to extend into areas of memory other than the region of memory that is specified when the program starts, you can redefine the function __user_heap_extend().

__user_heap_extend() returns blocks of memory for heap usage in extending the size of the heap.

Non-ConfidentialPDF file icon PDF versionARM DUI0475M
Copyright © 2010-2016 ARM Limited or its affiliates. All rights reserved.