First time gcc linker script for microcontroller compiles but doesn't run

0

I created my first gcc linker script for a SAMD51J19 microcontroller through atmel studio and it compiles great without issues but when loaded into the device weird quirky errors happen.

Sometimes it hard-faults, sometimes it doesn't, sometimes interrupts aren't sent to the handler, sometimes they are. Sometimes functions are run with nothing happening like it should and sometimes not. The debugger was all over the place, I didn't have any of these problems with the old stock linker code and I have no idea why it's happening.

Most all of it was just re-used from the original file. Mainly what I did was add some spacing or better alignment between areas and moved some sections around that weren't mandatory placed there. For example Read-Only data at the end of rom bank 0 rather than the middle. so I really don't get why this is happening

below is my linker script

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)

/*
 * NVM = 2 Banks (512KB) (352KB usable) (160KB reserved for SEEPROM)
 * 1 Bank = 32 blocks (256K) and 16 Regions
 *    Bank 1 (Main) = 32 blocks (256K) and 16 Regions
 *    Bank 2 (Aux)  = 12 Blocks (96KB) and 6 Regions
 * 1 Region = 2 Blocks (16KB) (Protection Alignment)
 * 1 Block = 16 Pages (8KB) (Division Alignment)
 * 1 Page = 32 QWords (512B) (Section Alignment)
 * 1 QWord = 16 Bytes (Sub-Section Alignment)
 * 1 DWord = 8 Bytes
 * 1 Word  = 4 Bytes (Default Alignment)
 *
 * Alignments:
 * 4      Bytes: New piece
 * 16     Bytes: New Subsection
 * 512    Bytes: New Section
 * 8,192  Bytes: New division
 * 16,384 Bytes: New protection region
*/

/* Memory Spaces Definitions */
MEMORY
{
  rom0     (rx)  : ORIGIN = 0x00000000, LENGTH = 0x0003F800 /*Rom Bank 0: Main Bank (For Code)*/
    lnl      (rx)  : ORIGIN = 0x0003F800, LENGTH = 0x00000800 /*Load-N-Lock 0-Wait State Speed: 2KB*/

  rom1     (rx)  : ORIGIN = 0x00040000, LENGTH = 0x00018000 /*Rom Bank 1: Aux Bank (For Data)*/
  qspi     (rx)  : ORIGIN = 0x04000000, LENGTH = 0x01000000 /*External NVM: (Additional Aux Data on seperate chip)*/
  ram      (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000 /*Ram (Default RAM)*/
  seeprom  (rx)  : ORIGIN = 0x44000000, LENGTH = 0x00010000 /*SEEPROM: Runtime Permanent Data*/
  bkupram  (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000 /*Backup Ram: Program Data*/
}

/* The stack size used by the application*/
STACK_SIZE = 0xC000;

/* Section Definitions */
SECTIONS
{
  /*
    Program Code

    Gameplan for .text output section

    No support for exceptions or unwinding tables

    Vectors go at start
    Program Code is placed on the next QWord
    Thumb/Arm Glue code is placed on the next QWord
    Read-Only Data is placed in it's own page
    Relocate Data is placed in it's own page
  */
  .text :
  {
    /*Start at top*/
    . = 0x00000000;
    _stext = .;
    _sfixed = .;

    /*Vector Table*/
    /*Place Vectors at start of rom0 as required*/
    KEEP(*(.vectors .vectors.*))

    /*Program Code*/
    . = ALIGN(16); /*New Subsection*/
    *(.text .text.* .gnu.linkonce.t.*)

    /*C & C++ Special Generated Code, part of main program code*/

    /*C++ Setup Code*/
    . = ALIGN(4); /*New piece*/
    KEEP(*(.init))

    . = ALIGN(4); /*New piece*/
    __preinit_array_start = .;
    KEEP (*(.preinit_array))
    __preinit_array_end = .;

    . = ALIGN(4); /*New piece*/
    __init_array_start = .;
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array))
    __init_array_end = .;

    /*C++ Constructor Code*/
    . = ALIGN(4); /*New piece*/
    KEEP (*crtbegin.o(.ctors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*crtend.o(.ctors))

    /*C++ Teardown Code*/
    . = ALIGN(4); /*New piece*/
    KEEP(*(.fini))

    . = ALIGN(4); /*New piece*/
    __fini_array_start = .;
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    __fini_array_end = .;

    /*C++ Deconstructor Code*/
    . = ALIGN(4); /*New piece*/
    KEEP (*crtbegin.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*crtend.o(.dtors))

    /*Thumb <==> ARM Code Translation Glue*/
    . = ALIGN(16); /*New Subsection*/
    *(.glue_7t) *(.glue_7)

    /*Read-Only/Constant Data, placing in a new page*/
    . = ALIGN(512); /*New Page*/
    *(.rodata .rodata* .gnu.linkonce.r.*)

    /*This is for relocating data, place it in it's own page*/
    . = ALIGN(512); /*New Page*/
    _placeRelocate = .;

    _efixed = .;
    _etext = .;
  } > rom0 /*These of course go in the main rom bank*/

  /*
    Rom 0 Custom Code

    Gameplan for .rom0 output section

    This is sort of a workarea for program-specific usage unrelated to generated
    code. It needs to go into it's own block.
  */
  .rom0 (NOLOAD):
  {
    . = ALIGN(8192); /*New block*/
    _srom0 = .;
    *(.rom0*)
    _erom0 = .;
  } > rom0

  /*
    Load-N-Lock 0-Wait State Speed

    Gameplan for .lnl output section

    LNL is placed in it's own reserved memory area of a specific size in rom0. Space is
    immensely cramped and every byte counts. No alignment will be done.
  */
  .lnl (NOLOAD):
  {
    _slnl = .;
    *(.lnl*)
    _elnl = .;
  } > lnl /*Goes into it's own specific area*/

  /*
    Rom 1 Custom Code

    Gameplan for .rom1 output section

    Rom Bank 1 is more relaxed given the entire bank is for program usage.
    This needs to be placed after the first page. The first page is reserved
    for program-specific header data and work area.
  */
  .rom1 (NOLOAD):
  {
    . = 512; /*2nd page from start*/
    _srom1 = .;
    *(.rom1*)
    _erom1 = .;
  } > rom1 /*Goes into rom bank 1*/

  /*
    QSPI Custom Code

    Gameplan for .qspi output section

    QSPI is similar to ROM1 in that it's just an area that can be used
    for custom usage or work area.
  */
  .qspi (NOLOAD):
  {
    . = ALIGN(4); /*New piece*/
    _sqspi = .;
    *(.qspi*)
    _eqspi = .;
  } > qspi /*Goes into QSPI*/

  /*
    Uninitialized Data

    Gameplan for .bss output section

    Uninitialized data goes into main RAM at the start
  */
  .bss (NOLOAD) :
  {
    . = ALIGN(4); /*New piece*/
    _sbss = . ;
    _szero = .;
    *(.bss .bss.*) /*Place BSS Data at start of RAM*/

    . = ALIGN(4); /*New piece*/
    *(COMMON) /*Place common data after*/
    _ebss = . ;
    _ezero = .;

    /*Relocate data comes after bss*/
    . = ALIGN(4); /*New piece*/
    _relocateStart = .;
  } > ram

  /*
    Relocate data

    Gameplan for .relocate output section

    This needs to be placed at rom0 in it's own defined section. It will
    be copied to the end of bss.
  */
  .relocate : AT (_placeRelocate)
  {
    . = ALIGN(4); /*New piece*/
    _srelocate = .;
    *(.data .data.*);

    . = ALIGN(4); /*New Piece*/
    *(.ramfunc .ramfunc.*);
    _erelocate = .;
  } > ram /*Place in RAM*/

  /*
    Stack data

    Gameplan for .stack output section

    Placed at end of RAM an empty area large enough for the stack
  */
  .stack (NOLOAD):
  {
    . = ALIGN(8); /*New larger piece*/
    _sstack = .; /*Begin Stack*/

    . = . + STACK_SIZE; /*Insert large blank area for stack*/

    . = ALIGN(8); /*New larger piece*/
    _estack = .; /*End stack placement*/
  } > ram

  /*
    SEEPROM Data

    Gameplan for .seeprom output section

    The SEEPROM section is like rom1 just byte-writable rather than
    block/page eraseable/writable. Unlike ROM1 however SEEPROM can start
    at the beginning.
  */
  .seeprom (NOLOAD):
  {
    . = ALIGN(4); /*New piece*/
    _seeprom = .;
    *(.seeprom*)
    _eseeprom = .;
  } > seeprom /*Goes into seeprom area*/

  /*
    Custom Backup RAM

    Gameplan for .bkupram output section

    Like ROM1 and SEEPROM, this is another potential usage area.
  */
  .bkupram (NOLOAD):
  {
    . = ALIGN(4); /*New piece*/
    _sbkupram = .;
    *(.bkupram*)
    _ebkupram = .;
  } > bkupram /*Goes into bkupram area*/

  . = ALIGN(4); /*New piece*/
  _end = . ; /*End of everything*/
}

And the original file here that came with the ide

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)

/* Memory Spaces Definitions */
MEMORY
{
  rom0     (rx)  : ORIGIN = 0x00000000, LENGTH = 0x0003F800
  lnl      (rx)  : ORIGIN = 0x0003F800, LENGTH = 0x00000800 /*Load-N-Lock 0-Wait State Caching: 2KB*/
  rom1     (rx)  : ORIGIN = 0x00040000, LENGTH = 0x00018000
  qspi     (rx)  : ORIGIN = 0x04000000, LENGTH = 0x01000000
  ram      (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000
  seeprom  (rx)  : ORIGIN = 0x44000000, LENGTH = 0x00010000
  bkupram  (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000
}

/* The stack size used by the application. NOTE: you need to adjust according to your application. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0xC000;

/* Section Definitions */
SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        _sfixed = .;
        KEEP(*(.vectors .vectors.*))
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
        *(.ARM.extab* .gnu.linkonce.armextab.*)

        /* Support C constructors, and C destructors in both user code
           and the C library. This also provides support for C++ code. */
        . = ALIGN(4);
        KEEP(*(.init))
        . = ALIGN(4);
        __preinit_array_start = .;
        KEEP (*(.preinit_array))
        __preinit_array_end = .;

        . = ALIGN(4);
        __init_array_start = .;
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        __init_array_end = .;

        . = ALIGN(4);
        KEEP (*crtbegin.o(.ctors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
        KEEP (*(SORT(.ctors.*)))
        KEEP (*crtend.o(.ctors))

        . = ALIGN(4);
        KEEP(*(.fini))

        . = ALIGN(4);
        __fini_array_start = .;
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        __fini_array_end = .;

        KEEP (*crtbegin.o(.dtors))
        KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
        KEEP (*(SORT(.dtors.*)))
        KEEP (*crtend.o(.dtors))

        . = ALIGN(4);
        _efixed = .;            /* End of text section */
    } > rom0

    /* .ARM.exidx is sorted, so has to go in its own output section.  */
    PROVIDE_HIDDEN (__exidx_start = .);
    .ARM.exidx :
    {
      *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > rom0
    PROVIDE_HIDDEN (__exidx_end = .);

    . = ALIGN(4);
    _etext = .;

    .lnl :
    {
      /*. = ALIGN(4);*/
        __lnl_start__ = .;
        *(.lnl*)
        __lnl_end__ = .;
    } > lnl

    .rom1 (NOLOAD):
    {
        . = ALIGN(8);
        _rom1 = .;
        *(.rom1 .rom1.*);
        . = ALIGN(8);
        _rom1 = .;
    } > rom1

    .seeprom (NOLOAD):
    {
        . = ALIGN(8);
        _seeprom = .;
        *(.seeprom .seeprom.*);
        . = ALIGN(8);
        _eseeprom = .;
    } > seeprom

    .relocate : AT (_etext)
    {
        . = ALIGN(4);
        _srelocate = .;
        *(.ramfunc .ramfunc.*);
        *(.data .data.*);
        . = ALIGN(4);
        _erelocate = .;
    } > ram

    .bkupram (NOLOAD):
    {
        . = ALIGN(8);
        _sbkupram = .;
        *(.bkupram .bkupram.*);
        . = ALIGN(8);
        _ebkupram = .;
    } > bkupram

    .qspi (NOLOAD):
    {
        . = ALIGN(8);
        _sqspi = .;
        *(.qspi .qspi.*);
        . = ALIGN(8);
        _eqspi = .;
    } > qspi

    /* .bss section which is used for uninitialized data */
    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        _sbss = . ;
        _szero = .;
        *(.bss .bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = . ;
        _ezero = .;
    } > ram

    /* stack section */
    .stack (NOLOAD):
    {
        . = ALIGN(8);
        _sstack = .;
        . = . + STACK_SIZE;
        . = ALIGN(8);
        _estack = .;
    } > ram

    . = ALIGN(4);
    _end = . ;
}
c++
gcc
embedded
atmel
linker-scripts
asked on Stack Overflow Oct 16, 2019 by June

1 Answer

0

It turns out after much experimentation, trial, and error that the ram section have to seemingly be "relocate" then "bss" then "stack" in that order.

What I was trying to do was place "bss" above "relocate" and that caused everything to not work. So that's the answer but can anybody explain why "bss" has to be above "relocate". I did that because I was wanting static members to be placed at the top and I understand relocate is for non-static members.

answered on Stack Overflow Oct 16, 2019 by June

User contributions licensed under CC BY-SA 3.0