Board not running with external heap (Linker script)

Asked by Brob

Hello,

I'm trying the following:

I have a Stm32 chip with an additional 512KB external RAM. I would like to use the internal RAM for stack and the external RAM for heap. If I fit everything into the internal RAM it works fine, if I fit everything into the external RAM it works fine, but when I try to split the functionality between the two parts it does not work. I'm pretty sure my hardware is ok (I'm moving from different compiler to GCC ARM Embedded).

One of the things from other forums; I tried modifying _sbrk to not check for overlaps but that didn't work out.

Anyone has a suggestion? Thanks.

This the linker script I used in the non-working case (Actually all I did was defining + moving the heap to the external RAM):

/* Linker script to configure memory regions. */
MEMORY
{
  EXTERNALRAM (rwx) : ORIGIN = 0x68000000, LENGTH = 512k
  FLASH (rx) : ORIGIN = 0x08006000, LENGTH = 488k
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
  option_bytes_rom (rx) : ORIGIN = 0x1FFFF800, LENGTH = 16
}

/* Library configurations */
GROUP(libgcc.a libc.a libm.a libnosys.a)

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory regions FLASH and RAM.
 * It references following symbols, which must be defined in code:
 * Reset_Handler : Entry of reset handler
 *
 * It defines following symbols, which code can use without definition:
 * __exidx_start
 * __exidx_end
 * __copy_table_start__
 * __copy_table_end__
 * __zero_table_start__
 * __zero_table_end__
 * __etext
 * __data_start__
 * __preinit_array_start
 * __preinit_array_end
 * __init_array_start
 * __init_array_end
 * __fini_array_start
 * __fini_array_end
 * __data_end__
 * __bss_start__
 * __bss_end__
 * __end__
 * end
 * __HeapLimit
 * __StackLimit
 * __StackTop
 * __stack
 * __Vectors_End
 * __Vectors_Size
 */
ENTRY(Reset_Handler)

SECTIONS
{
 .text :
 {
  KEEP(*(.vectors))
  __Vectors_End = .;
  __Vectors_Size = __Vectors_End - __Vectors;
  __end__ = .;

  *(.text*)

  KEEP(*(.init))
  KEEP(*(.fini))

  /* .ctors */
  *crtbegin.o(.ctors)
  *crtbegin?.o(.ctors)
  *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
  *(SORT(.ctors.*))
  *(.ctors)

  /* .dtors */
   *crtbegin.o(.dtors)
   *crtbegin?.o(.dtors)
   *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
   *(SORT(.dtors.*))
   *(.dtors)

  *(.rodata*)

  KEEP(*(.eh_frame*))
 } > FLASH

 .ARM.extab :
 {
  *(.ARM.extab* .gnu.linkonce.armextab.*)
 } > FLASH

 __exidx_start = .;
 .ARM.exidx :
 {
  *(.ARM.exidx* .gnu.linkonce.armexidx.*)
 } > FLASH
 __exidx_end = .;

 /* To copy multiple ROM to RAM sections,
  * uncomment .copy.table section and,
  * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S
 .copy.table : ALIGN (4)
 {
  . = ALIGN(4);
  __copy_table_start__ = .;
  LONG (__etext)
  LONG (__data_start__)
  LONG (__data_end__ - __data_start__)
  LONG (__etext2)
  LONG (__data2_start__)
  LONG (__data2_end__ - __data2_start__)
  __copy_table_end__ = .;
 } > FLASH
 */
 /* To clear multiple BSS sections,
  * uncomment .zero.table section and,
  * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S
 .zero.table : ALIGN (4)
 {
  . = ALIGN(4);
  __zero_table_start__ = .;
  LONG (__bss_start__)
  LONG (__bss_end__ - __bss_start__)
  LONG (__bss2_start__)
  LONG (__bss2_end__ - __bss2_start__)
  __zero_table_end__ = .;
 } > FLASH
 */
 __etext = .;

 .data : AT (__etext)
 {
  __data_start__ = .;
  *(vtable)
  *(.data*)

  . = ALIGN(4);
  /* preinit data */
  PROVIDE_HIDDEN (__preinit_array_start = .);
  KEEP(*(.preinit_array))
  PROVIDE_HIDDEN (__preinit_array_end = .);

  . = ALIGN(4);
  /* init data */
  PROVIDE_HIDDEN (__init_array_start = .);
  KEEP(*(SORT(.init_array.*)))
  KEEP(*(.init_array))
  PROVIDE_HIDDEN (__init_array_end = .);

  . = ALIGN(4);
  /* finit data */
  PROVIDE_HIDDEN (__fini_array_start = .);
  KEEP(*(SORT(.fini_array.*)))
  KEEP(*(.fini_array))
  PROVIDE_HIDDEN (__fini_array_end = .);

  KEEP(*(.jcr*))
  . = ALIGN(4);
  /* All data end */
  __data_end__ = .;

 } > RAM

 .bss : ALIGN (8)
 {
  . = ALIGN(4);
  __bss_start__ = .;
  *(.bss*)
  *(COMMON)
  . = ALIGN(4);
  __bss_end__ = .;
 } > RAM

 .heap (COPY): ALIGN (8)
 {
  __HeapBase = .;
  __end__ = .;
  end = __end__;
  KEEP(*(.heap*))
  __HeapLimit = .;
 } > EXTERNALRAM

 /* .stack_dummy section doesn't contains any symbols. It is only
  * used for linker to calculate size of stack sections, and assign
  * values to stack symbols later */
 .stack_dummy (COPY): ALIGN (8)
 {
  KEEP(*(.stack*)) /* changed MG 30.05.14 */
 } > RAM

 /* Set stack top to end of RAM, and stack limit move down by
  * size of stack_dummy section */
 __StackTop = ORIGIN(RAM) + LENGTH(RAM);
 __StackLimit = ORIGIN(RAM);
 PROVIDE(__stack = __StackTop);
}

Question information

Language:
English Edit question
Status:
Solved
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Solved by:
Brob
Solved:
Last query:
Last reply:
Revision history for this message
Andre Vieira (andre-simoesdiasvieira) said :
#1

Hi Brob,

Our sbrk implementation assumes that the heap and the stack grow towards each other. It uses that assumption to check whether the next heap_end and stack pointer have crossed each other, i.e. whether heap_end + incr > stack_ptr and if thats the case it assumes it is out of memory causing the malloc that uses it to return a null pointer.

In your case, the address of the heap is always larger than the stack pointer so it thinks its always out of memory.
_sbrk has the weak attribute so you could overwrite it. You can find the source for _sbrk in our source tarball, download it, untar newlib and look at newlib/libgloss/arm/syscalls.c.

Hope this helps.

Cheers,
Andre

Revision history for this message
Brob (tlj-debrouwer) said :
#2

Thanks Andre,

This solved it for the easy situation (so when I have a single binary in flash), I removed the check from _sbrk and compiled it into the library. Runs as before.