Link variable at specific address

1

I'm writing an application for an embedded system using an Atmel ARM core processor using GCC tools provided with Atmel Studio. The production programming device I'll be using can write a serial number to a specified ROM location during programming which is nice because it's an automated process and avoids the potential for human error.

I'd like to set aside space in my binary to ensure that a given address is ALWAYS free for this purpose, and also so that my application can read its serial number from Flash.

I've looked at some other questions on SO such as this one that appear very similar to my problem but seem to omit key details from the answers because I am unable to reproduce the results.

The linker script that was provided for my processor is as follows:

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

/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)  : ORIGIN = 0x00400000, LENGTH = 0x00800000
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}

/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;

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 */
    } > rom

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

    . = 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

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

This script works with no problems. I've attempted to add a small section of memory to store the serial number in Flash but always end up with the linker happily storing data well outside the specified rom area.

I have tried adding code to the linker script as follows:

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

/**** START ADDED CODE ****/    
_metastart = 0x47FF00;
.metadata :
{
    . = _metastart;
    *(.metadata)  
} > rom
/**** END ADDED CODE ****/

. = ALIGN(4);
_etext = .;

.relocate : AT (_etext)
{

and to my main.cpp like this:

static uint8_t nvSerial[4] __attribute__((used,section(".metadata"))) = { 0xDE, 0xAD, 0xBE, 0xEF };

But end up with a huge binary file with data well above 0x00480000 and below 0x200000000. I've also tried writing the linker script addition as follows (in the same location as above):

_metastart = 0x47FF00;
.metadata : AT(_metastart)
{
    *(.metadata)  
} > rom

But then my serial number seems to be left out entirely (i.e., there's nothing present at 0x47FF00). Similarly, there's no data to be found if I set up my linker file like this:

MEMORY
{
  rom (rx)  : ORIGIN = 0x00400000, LENGTH = 0x0007FF00
  meta (rx) : ORIGIN = 0x0047FF00, LENGTH = 0x00000100 /** ADDED **/
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/** snip **/
.metadata :
{
    *(.metadata)  
} > meta

Can anyone offer any advice as to what I'm doing wrong?

EDIT

So the "solution" to the problem was to change my linker to make use of the KEEP command to describe the metadata section AFTER the value of _etext gets updated. If I describe metadata BEFORE _etext gets assigned, then the linker for some reason stores a bunch of constant data after metadata and into an undefined memory region. Relevant sections of the new linker file are below:

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

/* Memory Spaces Definitions */
MEMORY
{
  rom (rx)  : ORIGIN = 0x00400000, LENGTH = 0x0007FF00
  meta (rx) : ORIGIN = 0x0047FF00, LENGTH = 0x00000100
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}

/** snip **/

. = ALIGN(4);
_etext = .;

.metadata :
{
    KEEP(*(.metadata))
} > meta

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

So this works but my question is now WHY does this work?

c++
c
gcc
linker
embedded
asked on Stack Overflow Apr 28, 2016 by CodingHero • edited May 23, 2017 by Community

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0