cgcclinkerstm32f3

STM32 GCC linker OVERLAY command does not form segments (sizes and load addresses) correctly


I tried to follow this tutorial to make something similar on STM32F303. I dedicate 4 KiB of CCMRAM to the overlay region:

MEMORY
{
  FLASH (rx)                : ORIGIN = 0x08000000, LENGTH = 512K
  RAM (xrw)                 : ORIGIN = 0x20000000, LENGTH = 64K
  MEMORY_B1 (rx)            : ORIGIN = 0x60000000, LENGTH = 0K
  CCMRAM (xrw)              : ORIGIN = 0x10000000, LENGTH = 12K
  
  CCMRAM_OVERLAY (xrw)      : ORIGIN = 0x10003000, LENGTH = 4K
}

Then I define overlay:

/* Define output sections */
SECTIONS
{
  /* overlays */
  OVERLAY : NOCROSSREFS
  {
    .eff1  { src/effects/effect1.o(.text .data) }
    .eff2  { src/effects/effect2.o(.text .data) }
  } >CCMRAM_OVERLAY AT>FLASH

Then I try to place addresses and lengths table into RAM:

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    
    __eff_table = .; 
        LONG(ABSOLUTE(ADDR(.eff1))); LONG(SIZEOF(.eff1)); LONG(LOADADDR(.eff1));
        LONG(ABSOLUTE(ADDR(.eff2))); LONG(SIZEOF(.eff2)); LONG(LOADADDR(.eff2));
        
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

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

Functions themselves end up in FLASH as they should but in .map file I see that the load addresses are snapped to the beginning of the FLASH and that the sizes of both segments are zero:

.eff1           0x10003000        0x0 load address 0x08000000
 src/effects/effect1.o(.text .data)
                [!provide]                PROVIDE (__load_start_eff1, LOADADDR (.eff1))
                [!provide]                PROVIDE (__load_stop_eff1, (LOADADDR (.eff1) + SIZEOF (.eff1)))

.eff2           0x10003000        0x0 load address 0x08000000
 src/effects/effect2.o(.text .data)
                [!provide]                PROVIDE (__load_start_eff2, LOADADDR (.eff2))
                [!provide]                PROVIDE (__load_stop_eff2, (LOADADDR (.eff2) + SIZEOF (.eff2)))
.data           0x20000000       0x2c load address 0x08000564
                0x20000000                . = ALIGN (0x4)
                0x20000000                _sdata = .
                0x20000000                __eff_table = .
                0x20000000        0x4 LONG 0x10003000 ABSOLUTE (ADDR (.eff1))
                0x20000004        0x4 LONG 0x0 SIZEOF (.eff1)
                0x20000008        0x4 LONG 0x8000000 LOADADDR (.eff1)
                0x2000000c        0x4 LONG 0x10003000 ABSOLUTE (ADDR (.eff2))
                0x20000010        0x4 LONG 0x0 SIZEOF (.eff2)
                0x20000014        0x4 LONG 0x8000000 LOADADDR (.eff2)

Meanwhile the functions are located there (not at the beginning of Flash, of course, and they have non-zero length): enter image description here

My question is: how to make it work? I want functions to be compiled in such a way that I can copy them to CCMRAM and call them, and I want their addresses and lengths array to be properly filled at compilation time. What I am doing wrong? I don't have much experience with linker scripts but in previous project I managed to just copy and execute functions in CCMRAM once. But here I want to swap functions at the same memory location in runtime.

Here is my entire project (made in Atollic TrueSTUDIO).


Solution

  • I managed to make it work. You need to replace

    /* Define output sections */
    SECTIONS
    {
      /* overlays */
      OVERLAY : NOCROSSREFS
      {
        .eff1  { src/effects/effect1.o(.text .data) }
        .eff2  { src/effects/effect2.o(.text .data) }
      } >CCMRAM_OVERLAY AT>FLASH
    

    with

    /* Define output sections */
    SECTIONS
    {
      /* The startup code goes first into FLASH */
      .isr_vector :
      {
        . = ALIGN(4);
        KEEP(*(.isr_vector)) /* Startup code */
        . = ALIGN(4);
      } >FLASH
      
      /* overlays */
      OVERLAY : NOCROSSREFS
      {
        .eff1  { src/effects/effect1.o(.text .text* .data .data*) }
        .eff2  { src/effects/effect2.o(.text .text* .data .data*) }
      } >CCMRAM_OVERLAY AT>FLASH
    

    ISR vectors table goes first, otherwise the program won't start!

    I tested it on real hardware (it works), and now map file looks correct:

    .data           0x20000000       0x2c load address 0x08000578
                    0x20000000                . = ALIGN (0x4)
                    0x20000000                _sdata = .
                    0x20000000                __eff_table = .
                    0x20000000        0x4 LONG 0x10003000 ABSOLUTE (ADDR (.eff1))
                    0x20000004        0x4 LONG 0x34 SIZEOF (.eff1)
                    0x20000008        0x4 LONG 0x8000194 LOADADDR (.eff1)
                    0x2000000c        0x4 LONG 0x10003000 ABSOLUTE (ADDR (.eff2))
                    0x20000010        0x4 LONG 0x34 SIZEOF (.eff2)
                    0x20000014        0x4 LONG 0x80001c8 LOADADDR (.eff2)
    

    As you can see, .eff1 and .eff2 now come directly after ISR vector table (which is precisely 0x194 bytes long) and have valid sizes (both functions are LED blinks with busy waits but have different busy-wait delays).