GNU LD Linker - Cannot get variable In flash at Address

3

I'm working with a STM32F072 and need to add a structure to a specific location in Flash. But the structure doesn't get programmed to flash when the address is 0x0801F800.

I declare an instance at namespace scope:

const Memory ConfigData __attribute__ ((section (".ConfigData"))) __attribute__ ((__used__)){ 2u, 1.0f, 0.1f, 1.0f, 12.0f, 2.5f };

To insert the above at a specific memory location i'm using:

_ConfigStart = 0x0801F800;
.ConfigData _ConfigStart :
{
    KEEP(*(.ConfigData));
} > FLASH

The above code does not work however, when the _ConfigStart address is 0x0800F800 it does work. But I need it to be in the last page of flash (0x0801F800) so that isn't a workable option.

I am able to use the STLINK-V2 to manually program the page I want and I can also use my own flash library to do it but I need it to be included by the linker.

There are no linker errors at this point.

Linker files: mem.ld:

MEMORY
{
  RAM (xrw)     : ORIGIN = 0x20000000, LENGTH = 16K
  CCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 0
  FLASH (rx)    : ORIGIN = 0x08000000, LENGTH = 128K
  FLASHB1 (rx)  : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  MEMORY_ARRAY (xrw)  : ORIGIN = 0x00000000, LENGTH = 0
}

sections.ld(some things cut out for brevity):

__stack = ORIGIN(RAM) + LENGTH(RAM);
_estack = __stack;  /* STM specific definition */

/*
 * Default stack sizes.
 * These are used by the startup in order to allocate stacks 
 * for the different modes.
 */
__Main_Stack_Size = 1024 ;

PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ;
__Main_Stack_Limit = __stack  - __Main_Stack_Size ;

PROVIDE ( _Main_Stack_Limit = __Main_Stack_Limit ) ;
_Minimum_Stack_Size = 256 ;


PROVIDE ( _Heap_Begin = _end_noinit ) ;
PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ;
ENTRY(_start)


SECTIONS
{
    .isr_vector : ALIGN(4)
    {
        FILL(0xFF)

        __vectors_start = ABSOLUTE(.) ;
        __vectors_start__ = ABSOLUTE(.) ; /* STM specific definition */
        KEEP(*(.isr_vector))        /* Interrupt vectors */

        KEEP(*(.cfmconfig))         /* Freescale configuration words */   

        *(.after_vectors .after_vectors.*)  /* Startup code and ISR */

    } >FLASH

    .inits : ALIGN(4)
    {
        /* 
         * Memory regions initialisation arrays.
         *
         * Thee are two kinds of arrays for each RAM region, one for 
         * data and one for bss. Each is iterated at startup and the   
         * region initialisation is performed.
         * 
         * The data array includes:
         * - from (LOADADDR())
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * The bss array includes:
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * WARNING: It is mandatory that the regions are word aligned, 
         * since the initialisation code works only on words.
         */

        __data_regions_array_start = .;

        LONG(LOADADDR(.data));
        LONG(ADDR(.data));
        LONG(ADDR(.data)+SIZEOF(.data));

        LONG(LOADADDR(.data_CCMRAM));
        LONG(ADDR(.data_CCMRAM));
        LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM));

        __data_regions_array_end = .;

        __bss_regions_array_start = .;

        LONG(ADDR(.bss));
        LONG(ADDR(.bss)+SIZEOF(.bss));

        LONG(ADDR(.bss_CCMRAM));
        LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM));

        __bss_regions_array_end = .;

        /* End of memory regions initialisation arrays. */

        /*
         * These are the old initialisation sections, intended to contain
         * naked code, with the prologue/epilogue added by crti.o/crtn.o
         * when linking with startup files. The standalone startup code
         * currently does not run these, better use the init arrays below.
         */
        KEEP(*(.init))
        KEEP(*(.fini))

        . = ALIGN(4);

        /*
         * The preinit code, i.e. an array of pointers to initialisation 
         * functions to be performed before constructors.
         */
        PROVIDE_HIDDEN (__preinit_array_start = .);

        /*
         * Used to run the SystemInit() before anything else.
         */
        KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))

        /* 
         * Used for other platform inits.
         */
        KEEP(*(.preinit_array_platform .preinit_array_platform.*))

        /*
         * The application inits. If you need to enforce some order in 
         * execution, create new sections, as before.
         */
        KEEP(*(.preinit_array .preinit_array.*))

        PROVIDE_HIDDEN (__preinit_array_end = .);

        . = ALIGN(4);

        /*
         * The init code, i.e. an array of pointers to static constructors.
         */
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))
        PROVIDE_HIDDEN (__init_array_end = .);

        . = ALIGN(4);

        /*
         * The fini code, i.e. an array of pointers to static destructors.
         */
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP(*(SORT(.fini_array.*)))
        KEEP(*(.fini_array))
        PROVIDE_HIDDEN (__fini_array_end = .);

    } >FLASH

    .flashtext : ALIGN(4)
    {
        *(.flashtext .flashtext.*)  /* Startup code */
    } >FLASH

    .text : ALIGN(4)
    {
        *(.text .text.*)            /* all remaining code */

        /* read-only data (constants) */
        *(.rodata .rodata.* .constdata .constdata.*)        

        *(vtable)                   /* C++ virtual tables */

        KEEP(*(.eh_frame*))

        *(.glue_7)
        *(.glue_7t)

    } >FLASH


    /* ARM magic sections */
    .ARM.extab : ALIGN(4)
    {
       *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > FLASH


    . = ALIGN(4);
    __exidx_start = .;      
    .ARM.exidx : ALIGN(4)
    {
       *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > FLASH

    __exidx_end = .;

    . = ALIGN(4);
    _etext = .;
    __etext = .;

    .data_CCMRAM : ALIGN(4)
    {
       FILL(0xFF)
       *(.data.CCMRAM .data.CCMRAM.*)
       . = ALIGN(4) ;
    } > CCMRAM AT>FLASH

    _sidata = LOADADDR(.data);

    .data : ALIGN(4)
    {
        FILL(0xFF)
        /* This is used by the startup code to initialise the .data section */
        _sdata = . ;            /* STM specific definition */
        __data_start__ = . ;
        *(.data_begin .data_begin.*)

        *(.data .data.*)

        *(.data_end .data_end.*)
        . = ALIGN(4);

        /* This is used by the startup code to initialise the .data section */
        _edata = . ;            /* STM specific definition */
        __data_end__ = . ;

    } >RAM AT>FLASH

    _ConfigStart = 0x0801F800;
    .ConfigData _ConfigStart :
    {
        KEEP(*(.ConfigData));
    } > FLASH

    .bss (NOLOAD) : ALIGN(4)
    {
        __bss_start__ = .;      /* standard newlib definition */
        _sbss = .;              /* STM specific definition */
        *(.bss_begin .bss_begin.*)

        *(.bss .bss.*)
        *(COMMON)

        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;        /* standard newlib definition */
        _ebss = . ;             /* STM specific definition */
    } >RAM

    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /*
     * DWARF debug sections.
     * Symbols in the DWARF debugging sections are relative to the beginning
     * of the section so we begin them at 0.  
     */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }    
}

ConfigData appears in the .map file here with address 0x0800f800:

 .igot.plt      0x20000078        0x0 c:/program files (x86)/gnu tools arm embedded/7 2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/thumb/v6-m\libstdc++_nano.a(new_op.o)

.ConfigData     0x0800f800       0x18
 *(.ConfigData)
 .ConfigData    0x0800f800       0x18 C:\Users\David\AppData\Local\Temp\cc10vcUe.ltrans0.ltrans.o

.rel.dyn        0x0800f818        0x0

And appears to get a size when allocated to 0x0801f800:

.igot.plt       0x20000078        0x0 load address 0x080090c8
 .igot.plt      0x20000078        0x0 c:/program files (x86)/gnu tools arm embedded/7 2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/thumb/v6-m\libstdc++_nano.a(new_op.o)

.ConfigData     0x0801f800       0x18
 *(.ConfigData)
 .ConfigData    0x0801f800       0x18 C:\Users\David\AppData\Local\Temp\ccIUhOBG.ltrans0.ltrans.o

.rel.dyn        0x0801f818        0x0
 .rel.iplt      0x0801f818        0x0 c:/program files (x86)/gnu tools arm embedded/7 2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/thumb/v6-m\libstdc++_nano.a(new_op.o)

I have also tried putting it into its own block:

.ConfigData :
    {
        KEEP(*(.ConfigData));
    } > CONFIG

With the mem.ld:

MEMORY
{
  RAM   (xrw)   : ORIGIN = 0x20000000,      LENGTH = 16K
  FLASH (rx)    : ORIGIN = 0x08000000,      LENGTH = 128K - 0x800
  CONFIG(R)     : ORIGIN = ORIGIN(FLASH) +  LENGTH(FLASH),  LENGTH = 0x800
}

No luck, really lost on this one.

EDIT

The issue was infact a strange quirk with this micro controller and the programmer. The programmer refuses to program beyond the flash range specified by the flash size register but the flash extends to 128K (not 64K). I have written to various addresses beyond the address range without issue and the reason I thought it was alright to do that was because the STLINK Utility allowed me to view that memory range.

This issue is specifically to-do with the STM32F072C8, and I'm not the only one with this confusion:

c++
c
linker
ld
stm32
asked on Stack Overflow Aug 7, 2018 by David Ledger • edited Dec 20, 2019 by marc_s

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0