2026-01-12 2:58 AM - last edited on 2026-01-12 3:09 AM by Andrew Neil
I am just curious about information in the flash.
#ifndef DEVICE_VERSIONING_INFORMATION_H
#define DEVICE_VERSIONING_INFORMATION_H
typedef struct {
uint32_t magic; // 0x46575652 = 'FWVR'
uint8_t major;
uint8_t minor;
uint8_t patch;
uint8_t build;
} fw_version_t;
__attribute__((used, section(".fw_version")))
const fw_version_t fw_version = {
.magic = 0x46575652,
.major = 1,
.minor = 3,
.patch = 2,
.build = 7,
};
#endif // DEVICE_VERSIONING_INFORMATION_H
I wrote in the linked script file (.ld) some versioning information. I guess it is the best way to store the device versioning information because that way allows the swd to get directly from the flash the version, although, I can get it too by request and response by uart.
However, why there is more data after the version information in the flash memory?
Is this normal? Should the user defined constants in the flash be followed by other information?
/*
******************************************************************************
**
** @file : LinkerScript.ld
**
** @author : Auto-generated by STM32CubeIDE
**
** Abstract : Linker script for NUCLEO-F070RB Board embedding STM32F070RBTx Device from stm32f0 series
** 128KBytes FLASH
** 16KBytes 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.
**
******************************************************************************
** @attention
**
** Copyright (c) 2026 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
******************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data into "FLASH" Rom type memory */
.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
/* Firmware version section at fixed address */
.fw_version 0x08003000 :
{
KEEP(*(.fw_version*))
} >FLASH
/* Constant data into "FLASH" Rom type memory */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
.preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
/* Used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections into "RAM" Ram type memory */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section into "RAM" Ram type memory */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_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
/* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the compiler libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}I just ask it out of curiosity.
Thanks for all.
Solved! Go to Solution.
2026-01-12 3:16 AM - edited 2026-01-12 3:18 AM
@Andrew Neil wrote:Please show your linker script - hard to comment on it without seeing it!
Ah, now you've edited the original post to add it!
You've only specified the location of your version information; you haven't said that it has to be the last thing in flash.
The Linker has seen that there is space available beyond your .fw_version section, so it has just used it as normal.
PS:
Where to find the official GNU ld and linker script documentation
via: https://stackoverflow.com/a/77868219
2026-01-12 3:08 AM
@carleslsregner wrote:I guess it is the best way to store the device versioning information because that way allows the swd to get directly from the flash
It's certainly a common way to do it.
@carleslsregner wrote:I wrote in the linker script file (.ld)
Please show your linker script - hard to comment on it without seeing it!
@carleslsregner wrote:why there is more data after the version information in the flash memory?
Why wouldn't there be?
What you've shown is all standard C stuff: .preinit_array, .init_array, etc are all part of the GCC startup process for initialising variables...
2026-01-12 3:16 AM - edited 2026-01-12 3:18 AM
@Andrew Neil wrote:Please show your linker script - hard to comment on it without seeing it!
Ah, now you've edited the original post to add it!
You've only specified the location of your version information; you haven't said that it has to be the last thing in flash.
The Linker has seen that there is space available beyond your .fw_version section, so it has just used it as normal.
PS:
Where to find the official GNU ld and linker script documentation
via: https://stackoverflow.com/a/77868219