Search code examples
gccarmgnuldstm32

GNU LD linker script - stack placement


Here is my linker script for a STM32L476:

/* Generate a link error if heap and stack don't fit into RAM */
__heap_size = 0x200;;      /* required amount of heap  */
__stack_size = 0x800;; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
    RAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 96K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .default_exceptions :
  {
    . = ALIGN(8);
    KEEP(*(.default_exceptions)) /* Startup code */
    . = ALIGN(8);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(8);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

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

    . = ALIGN(8);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(8);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(8);
  } >FLASH

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

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* The startup code goes first into FLASH */
  .exceptions :
  {
    . = ALIGN(8);
    KEEP(*(.exceptions)) /* RAM vector table */
    . = ALIGN(8);
  } >RAM

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(8);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(8);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  .heap :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    _sheap = .;
    . = . + __heap_size;
    . = ALIGN(4);
    _eheap = .;
  } >RAM

  .stack :
  {
    . = ALIGN(4);
    _estack = .;
    . = . + __stack_size;
    . = ALIGN(4);
    _sstack = .;
  } >RAM

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

The corresponding map file is:

.stack          0x20002844      0x800 load address 0x0801cc68
                0x20002844                . = ALIGN (0x4)
                0x20002844                _estack = .
                0x20003044                . = (. + __stack_size)
 *fill*         0x20002844      0x800 
                0x20003044                . = ALIGN (0x4)
                0x20003044                _sstack = .

I want to modify it in order that the stack is at the end of the RAM. I tried several ways (including the one discussed here but none is working. Even putting an hardcoded address returns an error ( the RAM goes up to 0x20018000 on this chip so it should fit ):

     .stack :
  {
    . = 0x20001000;
    _estack = .;
    . = . + __stack_size;
    . = ALIGN(4);
    _sstack = .;
  } >RAM

The error is:

20:01:46 **** Build of configuration Debug for project CardioNexion ****
make app=unit_test board=nucleo-l476rg V=1 all 
c:/program files (x86)/atollic/truestudio for stm32 9.0.0/armtools/bin/../lib/gcc/arm-atollic-eabi/6.3.1/../../../../arm-atollic-eabi/bin/ld.exe: region `RAM' overflowed by 536789060 bytes
collect2.exe: error: ld returned 1 exit status
make: *** [link] Error 1

20:01:50 Build Finished (took 4s.3ms)

Any idea what may cause the issue and how do do this ? (placing the stack at end of ram).


Solution

  • This "traditional" approach is not very good for the baremetal development.

    Much better is to place the stack at the beginning of the RAM. There is no danger of silent variable overwrite, stack overflow will generate the exception - and its routine can take the appropriate action (for example switch the device into "safe" mode, restart, emergency stop the controlled machine etc etc.