Question

Problem

My problem is that when I use the following script which is intended to place the Code into RAM the relocate section gets filled with bogus data.

My question is:

  1. Why is the _srelocate symbol 4 bytes greater than the _etext symbol? Shouldn't they be the same?

  2. Also, if the answer to 1. is NO, shouldn't I be copying from _etext + 4 to _srelocate?

Background and relevant code

I'm working with an Atmel ATSAM3N4X series processor (an ARM Cortex M3) and would like a little help with my linker script and .relocate section initialization.

The reason for this is that the _etext symbol is 4 bytes less than the _srelocate symbol.

The following linker script is the default script generated by Atmel Studio 6 (if you want the ram/rom symbol locations see the Apendix to the question).

/* ----------------------------------------------------------------------------
 *         SAM Software Package License
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

/* 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(0x4);
        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 */
    } > ram

    . = ALIGN(4);
    _etext = .;

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

    /* .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

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

    . = ALIGN(4);
    _end = . ;
}

I used nm to see what the symbol values were and I've included them below:

2000115c A _etext
20001160 D _srelocate
200015c8 D _erelocate

Now, Atmel Studio 6 auto-generated my project and gave me a Reset_Handler() that copies the .relocate section from _etext to _srelocate and clears the .bss section. The project came with two linker scripts, one for FLASH based execution and one for RAM based code. The default is the FLASH based code but I changed that to the RAM based linker script (provided above), and ran into the problem.

The initialization code that copies the .relocate section from FLASH to RAM is also auto-generated and I haven't changed it when I changed linker scripts. It looks like this:

void Reset_Handler(void)
{
    uint32_t *pSrc, *pDest, Size;

    /* Initialize the relocate segment */
    pSrc = &_etext;
    pDest = &_srelocate;

    if (pSrc != pDest) {
        for (; pDest < &_erelocate;) {
            *pDest++ = *pSrc++;
        }
    }

    /* Clear the zero segment */
    for (pDest = &_szero; pDest < &_ezero;) {
        *pDest++ = 0;
    }

    /* Set the vector table base address */
    pSrc = (uint32_t *) & _sfixed;
    SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk);

    if (((uint32_t) pSrc >= IRAM_ADDR) && ((uint32_t) pSrc < IRAM_ADDR + IRAM_SIZE)) {
        SCB->VTOR |= (1UL) << SCB_VTOR_TBLBASE_Pos;
    }

    /* Initialize the C library */
    __libc_init_array();

    /* Branch to main function */
    main();

    /* Infinite loop */
    while (1);
}

Edit 1:

Using objdump -t CodeFile.elf > CodeFile.symbols, I have found this symbol at the start of my .relocate section which seems to suggest that _srelocate doesn't truly point to the beginning of .relocate.

    2000115c g     O .relocate  00000000 .hidden __TMC_END__

What is this symbol?

I've looked it up and found this bug in GCC 4.7 but can't figure out if it is fixed or not in my version.

My compiler is arm-none-eabi-gcc and states its version as 4.7.0... The linker is arm-none-eabi-ld and its version is 2.22.

Edit 2:

I have done some research about this and it is recorded in this related SO question that I asked. Please look at it as well, as it explains that the problem is a GCC bug.

Apendix

Memory Layout for Linker Scripts

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

/* Memory Spaces Definitions */
MEMORY
{
    rom (rx)  : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash, 256K */
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00006000 /* sram, 24K */
}

/* The stack size used by the application. NOTE: you need to adjust  */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : 0x800 ;
Was it helpful?

Solution

I had long ago discovered the answer to my own question but it seems that it is still a little unclear in my edits so allow me to formalize it here.

The issue is that due to a bug in GCC the linker inserts an additional TMC_END symbol taking up 4 bytes in between my _etext and _srelocate symbols. This is incorrect because this symbol has nothing to do with the code that I'm writing and I'm not even using this functionality. I had discovered and explained this in my other SO question.

Workaround:

Atmel's sample code, rightly, assumes that if your code is running out of Flash memory your _srelocate symbol's address and _etext symbol's address will be different, one having an address starting with 0x004... and the other with 0x20....

If your code is running out of RAM, this means that you have a bootloader that copies the relevant sections into the correct memory location, hence the _etext symbol's address will also reside in RAM and be equal to the _srelocate symbol's address.

Therefore Atmel is trying to make sure that the _srelocate section always resides in RAM.

Due to the bug in GCC the solution was to change the code to check if the _srelocate symbol's address is already in RAM, like this:

// I can't remember what #define Atmel has for SRAM so I'm just going to
// use this one for the purposes of my example.
#define SRAM_START_ADDRESS 0x20000000

void Reset_Handler(void)
{
    uint32_t *pSrc, *pDest, Size;

    /* Initialize the relocate segment */
    pSrc = &_etext;      // Could either be in Flash or SRAM depending on your configuration.
    pDest = &_srelocate; // Always in SRAM or there's something strange going on...

    if ((intptr_t)pSrc < (intptr_t)SRAM_START_ADDRESS) { // <<<< Changed code here <<<<
        // We enter here only if pSrc is pointing to a location in Flash.
        // If that's the case, we need to copy the memory from Flash to SRAM.
        for (; pDest < &_erelocate;) {
            *pDest++ = *pSrc++;
        }
    }

    /* Clear the zero segment */
    for (pDest = &_szero; pDest < &_ezero;) {
        *pDest++ = 0;
    }

    /* Set the vector table base address */
    pSrc = (uint32_t *) & _sfixed;
    SCB->VTOR = ((uint32_t) pSrc & SCB_VTOR_TBLOFF_Msk);

    if (((uint32_t) pSrc >= IRAM_ADDR) && ((uint32_t) pSrc < IRAM_ADDR + IRAM_SIZE)) {
        SCB->VTOR |= (1UL) << SCB_VTOR_TBLBASE_Pos;
    }

    /* Initialize the C library */
    __libc_init_array();

    /* Branch to main function */
    main();

    /* Infinite loop */
    while (1);
}

And that worked for my situation. From what I can see this bug was fixed and the fix has since been reverted so it is unlikely that you will have it fixed in your Atmel Studio.

OTHER TIPS

I'm not sure if this is your issue, but if you are using SAM-BA to copy your code to SRAM, the SAM-BA boot program uses the first 2048 (0x800) bytes of SRAM for variables and its stack. Perhaps that is why your relocate section is getting stomped on (there are ISRs and other code still running while you copy the code, and these need their own SRAM).

All the SAM-BA applet examples get copied to 0x20000800 for this reason.

I don't know how else you'd place your code in SRAM, aside from implementing something similar to SAM-BA, in which case you'd also need your own section of SRAM for data.

Here is the linker script for the applets for the SAM4S16 part:

/* ----------------------------------------------------------------------------
 *         SAM Software Package License
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

/*------------------------------------------------------------------------------
 *      Linker script for running in internal SRAM on the SAM4S16
 *----------------------------------------------------------------------------*/

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

/* Memory Spaces Definitions */
MEMORY
{
    romcodesram (W!RX) : ORIGIN = 0x20000000, LENGTH = 0x800
    sram (W!RX) : ORIGIN = 0x20000800, LENGTH = 0x0001F800 /* sram, 128K - sizeof(romcodesram) */
}

SECTIONS
{
    /* startup code in the .isr_vector */
    .text :
    {
        . = ALIGN(4);
        _stext = .;
        KEEP(*(.isr_vector .isr_vector.*))
        *(.mailbox)
        *(.text .text.*)
        *(.rodata .rodata.*)
        *(.ramfunc .ramfunc.*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
        *(.rodata .rodata*)
        *(.gnu.linkonce.r.*)
        . = ALIGN(4);
        _etext = .;
    } > sram

    /* data */
    .data :
    {
        . = ALIGN(4);
        _sidata = .;
        _sdata = .;

        *(.data)
        *(.data.*)
        . = ALIGN(4);
        _edata = .;
    } > sram

    .bss (NOLOAD) : {
        _szero = .;
        *(.bss)
        . = ALIGN(4);
        _ezero = .;
    } >sram

    /* Stack in SRAM */
    _sstack = 0x2001FFF0;
}
. = ALIGN(4);
end = .;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top