Enemoino
Enemoino

Reputation: 11

Linker sector global variables addresing problem

I have already produced a work-around but I have a question about what is happening here. Setup:

  1. StmCUBEIDE (ver 10)
  2. Stm32F4 on custom board with lan
  3. 8Mb extra SDRAM
  4. 1Mb FLASH on single boot mode
    Default start from 0x08000000

Long story short I have sliced up my memory (flash) into sectors provided in linker. See linker below:

/*
*****************************************************************************
**

**  File        : LinkerScript.ld
**
**  Abstract    : Linker script for STM32F4xx Device with
**                1024Kbytes FLASH, 192Kbytes RAM
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used.
**
**  Target      : STMicroelectronics STM32
**
**
**  Distribution: The file is distributed as is, without any warranty
**                of any kind.
**
**  (c)Copyright Ac6.
**  You may use this file as-is or modify it according to the needs of your
**  project. Distribution of this file (unmodified or modified) is not
**  permitted. Ac6 permit registered System Workbench for MCU users the
**  rights to distribute the assembled, compiled & linked contents of this
**  file as part of an application binary file, provided that it is built
**  using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20030000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 128K;  /* required amount of heap  */
_Min_Stack_Size = 2K; /* required amount of stack */

/* Specify the memory areas
* reserved                           sector 0  (16kb sectors)
* flash (bootloader flash)           sector 4 & 5 (64kb + 128kb = 192kb)
* sectore stable                     sector 6 to 8 ( 128 +128 +128 = 384kb)
* sector latest                      sector 9 to 11 ( 128 +128 +128 = 384kb)
*   
*/
MEMORY
{
  FLASH_RESERVED (rxw): ORIGIN = 0x08000000, LENGTH = 16K
  FLASH_SX (rw) : ORIGIN = 0x08004000, LENGTH = 32K
  FLASH_COMMON  (rw) : ORIGIN = 0x0800C000, LENGTH = 16K
  FLASH_BOOTLOADER (rx)         : ORIGIN = 0x08010000, LENGTH = 192K 
  FLASH_STABLE (rxw)   : ORIGIN = 0x08040000, LENGTH = 384K
  FLASH_LATEST (rxw)   : ORIGIN = 0x080A0000, LENGTH = 384K
  RAM (rwx)          : ORIGIN = 0x20000000, LENGTH = 192K
  EXRAM (rwx)          : ORIGIN = 0xD0000000, LENGTH = 8192K
  
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH_BOOTLOADER */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH_BOOTLOADER
    /* keep this section for OTA capabilities*/
    .otaComBuff 0x08000000:
    {
        KEEP(*(.otaComBuff))
    } >FLASH_RESERVED = 0x00
    
  /* The program code and other data goes into FLASH_BOOTLOADER */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH_BOOTLOADER
  /* sectors for dual boot and reserved data */
    .reserved :
    {
        . = ALIGN(4);
        __reserved_start__ = .;
        KEEP(*(.reserved*))
        
        . = ALIGN(4);
        __reserved_end__ =  .;
    } >FLASH_RESERVED
    ASSERT(LENGTH(FLASH_RESERVED) >= (__reserved_end__ -__reserved_start__), "sector Reserved overflow")
    .sx (NOLOAD):
    {
        . = ALIGN(4);
        __sx_start__ = .;
        KEEP(*(.sx*))
        
        . = ALIGN(4);
        __sx_end__ =  .;
    } >FLASH_SX 
    ASSERT(LENGTH(FLASH_SX) >= (__sx_end__ -__sx_start__), "sector sx overflow")

    .common :
    {
        . = ALIGN(4);
        __common_start__ = .;
        KEEP(*(.common*))
        
        . = ALIGN(4);
        __common_end__ =  .;
    } >FLASH_COMMON
    ASSERT(LENGTH(FLASH_COMMON) >= (__common_end__ -__common_start__), "sector common overflow")

    .bootloader  :
    {
        . = ALIGN(4);
        __bootloader_start__ = .;
        KEEP(*(.bootloader*))
        
        . = ALIGN(4);
        __bootloader_end__ = .;
    } >FLASH_BOOTLOADER
    ASSERT(LENGTH(FLASH_BOOTLOADER) >= (__bootloader_end__ -__bootloader_start__), "sector bootloader overflow")

    .stable :
    {
        . = ALIGN(4);
        __stable_start__ = .;
        KEEP(*(.stable*))
        
        . = ALIGN(4);
        __stable_end__ = .;
    } >FLASH_STABLE 
    ASSERT(LENGTH(FLASH_STABLE) >= (__stable_end__ -__stable_start__), "sector stable overflow")

    .latest  :
    {
        . = ALIGN(4);
        __latest_start__ = .;
        KEEP(*(.latest*))
        
        . = ALIGN(4);
        __latest_end__ = .;
    } >FLASH_LATEST
    ASSERT(LENGTH(FLASH_LATEST) >= (__latest_end__ -__latest_start__), "sector latest overflow")

  /* Constant data goes into FLASH_BOOTLOADER */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH_BOOTLOADER

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH_BOOTLOADER
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH_BOOTLOADER

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH_BOOTLOADER
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH_BOOTLOADER
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH_BOOTLOADER

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

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

  
  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
    /* Uninitialized external data section */
  . = ALIGN(4);
  .extbss (NOLOAD):
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _extsbss = .;         /* define a global symbol at bss start */
    __extbss_start__ = _extsbss;
    *(.extbss)
    *(.extbss*)
    *(COMMON)

    . = ALIGN(4);
    _extebss = .;         /* define a global symbol at bss end */
    __extbss_end__ = _extebss;
  } >EXRAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    PROVIDE ( _max_heap = . );
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}



Next I have in my file:

#include "stm32f4xx_hal.h"
#include "stdint.h"
#include "FreeRTOS.h"
#include "task.h"
#include "error.h"
#include "debug.h"

extern unsigned int __bootloader_start__ ;
extern unsigned int __bootloader_end__ ;

extern unsigned int __sx_start__ ;
extern unsigned int __sx_end__ ;
/*external linker symbols for sector address feching*/
extern unsigned int __stable_start__ ;
extern unsigned int __stable_end__ ;
extern unsigned int __latest_start__ ;
extern unsigned int __latest_end__ ;
/*external linker symbol OTA flash region*/
extern unsigned int __reserved_start__ ;

#define ADR_SectorBootloaderStart ((uint32_t)(&__bootloader_start__))
#define ADR_SectorBootloaderEnd ((uint32_t)(&__bootloader_end_))

#define ADR_SectorSxStart ((uint32_t)(&__sx_start__))
#define ADR_SectorSxEnd ((uint32_t)(&__sx_end__))
#define ADR_SectorStableStart ((uint32_t)(&__stable_start__))
#define ADR_SectorStableEnd ((uint32_t)(&__stable_end__))
#define ADR_SectorLatestStart ((uint32_t)(&__latest_start__))
#define ADR_SectorLatestoEnd ((uint32_t)(&__latest_end__))
/*OTA communiaction sector*/
#define ADR_Reserved ((uint32_t)(&__reserved_start__))

Problem is that only ADR_SectorSxStart returns true address in other variables I get garbage.
On this variables depends flashing logic, for long time function for guarding bootloader sector was not working, after hardcoding addresses into function everything is OK. I need to make the rest of defines work. Any idea why it is that only one variable refers correctly?
Thank you.

@busybee
Map file gets the wrong address too:

.sx             0x0000000008004000        0x0
                0x0000000008004000                . = ALIGN (0x4)
                0x0000000008004000                __sx_start__ = .
 *(.sx*)
                0x0000000008004000                . = ALIGN (0x4)
                0x0000000008004000                __sx_end__ = .
                0x0000000000000001                ASSERT ((LENGTH (FLASH_SX) >= (__sx_end__ - __sx_start__)), sector sx overflow)

.common         0x000000000800c000        0x0
                0x000000000800c000                . = ALIGN (0x4)
                0x000000000800c000                __common_start__ = .
 *(.common*)
                0x000000000800c000                . = ALIGN (0x4)
                0x000000000800c000                __common_end__ = .
                0x0000000000000001                ASSERT ((LENGTH (FLASH_COMMON) >= (__common_end__ - __common_start__)), sector common overflow)

.bootloader     0x0000000008030a54        0x0
                0x0000000008030a54                . = ALIGN (0x4)
                0x0000000008030a54                __bootloader_start__ = .
 *(.bootloader*)
                0x0000000008030a54                . = ALIGN (0x4)
                0x0000000008030a54                __bootloader_end__ = .
                0x0000000000000001                ASSERT ((LENGTH (FLASH_BOOTLOADER) >= (__bootloader_end__ - __bootloader_start__)), sector bootloader overflow)

.stable         0x0000000008040000        0x0

Upvotes: 1

Views: 124

Answers (1)

Enemoino
Enemoino

Reputation: 11

After some time, I have found the answer. As per usual it was in plain .text in front of my eyes. The thing is that the address of SECTOR_BOOTLOADER is in fact placed correctly telling compiler where to place all .text variables.

When you go carefully line by line, you can see that I have actually created a memory region, FLASH_BOOTLOADER, and then used it as my main program address. This is correct. Then I have placed all my .text variables, using linker, then I created my REGION BOOTLOADER.

This is linker language means that in this region first he will place my variables, incrementing address and then he will place my sector, returning me address of sector not region.

This mistake was made by not understanding linker scripts and naming issue.

Upvotes: 0

Related Questions