Understanding ARM Cortex-M0+ relocation

901 views Asked by At

I'm just getting started with embedded arm development, and there's a snippet of code that's really bugging me:

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

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

Where _etext and _srelocate are symbols defined in the linker script:

. = ALIGN(4);
_etext = .;

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

Where ram is a memory segment whose origin is 0x20000000. The issue as I see it is that _etext is a symbol that marks the end boundary of the .text segment, which is a part of a different memory segment, rom. This means that unless the aforementioned memory segment was 100% full, _etext != _srelocate will always be true. What this means is that we're copying memory beyond the .text section where nothing is defined to live according to the linker script.

To me, this leads to one of three scenarios, either A) There is garbage present in rom beyond the .text section, and it gets copied into .relocate (and subsequently .data), or B) The memory beyond .text is empty following a chip erase operation prior to device programming, in which case .relocate is zeroed, or C) There is some slight of hand magic happening here where .data values are placed after .text in rom, and must be loaded into ram; in which case the comment should be s/relocate/data.

The third scenario seems the most likely, but according to the linker script this can't be true. Can someone shed some light on this?

1

There are 1 answers

0
Richard Pennington On BEST ANSWER

You're right, it's the third option. The AT() tells the linker to put the .ramfunc and .data sections (both of which are read/write) in the object file starting at _etext. The "> ram" tells the linker to resolve relocations as if the sections were placed in RAM this is done using a MEMORY command as decribed here: https://sourceware.org/binutils/docs/ld/MEMORY.html#MEMORY The result is that the copy loop moves the data from the read only area to the read/write area when the program starts up.

Here's a link to the gnu ld documentation where controlling the LMA (load address) is described: https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html