we have a strange issue on a Cortex M4 MCU. The compiled Firmware works if the binary is loaded with ST-LINK in the correct section, but using C-Lion and OpenOcd, The FW load operation, load also the ELF header in FLASH and corrupt a Flags Area used by a bootloader.
The MCU Flash is 512 kB - 256 pages total (2kB for page), with the following layout:
+-------- 0x0800 0000 - FLASH_BASE -------------------------+| Bootloader partition || |+-------- FLAGS_ADDR 0x0800 5000 --------------------------+| 1 page Flags page |+-------- APP_ADDR 0x0800 5800 -----------------------------+| || (APP_NUMPAGES) Application partition || |+-------- BAK_ADDR -----------------------------------------+| || (APP_NUMPAGES) Application backup || |+-------- NEW_ADDR -----------------------------------------+| || (APP_NUMPAGES) Update partition || |+-----------------------------------------------------------+
The App FW has to be loaded starting from 0x0800 8500
, that's true loading the .bin with ST-LINK, but loading the FW in C-Lion the code is correctly loaded starting from 0x0800 8500
, but also incorrectly the header of ELF file is loaded at 0x0800 5000
.
Analyzing the ELF file with readelf, shown the following information:
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .isr_vector PROGBITS 08005800 000800 000194 00 A 0 0 1 [ 2] .build_info PROGBITS 08005994 000994 0000a4 00 A 0 0 4 [ 3] .text PROGBITS 08005a40 000a40 01f698 00 AX 0 0 16 [ 4] .rodata PROGBITS 080250d8 0200d8 002540 00 A 0 0 4 [ 5] .ARM.extab PROGBITS 08027618 024398 000000 00 W 0 0 1 [ 6] .ARM ARM_EXIDX 08027618 022618 000008 00 AL 3 0 4 [ 7] .preinit_array PREINIT_ARRAY 08027620 024398 000000 04 WA 0 0 1 [ 8] .init_array INIT_ARRAY 08027620 022620 000038 04 WA 0 0 4 [ 9] .fini_array FINI_ARRAY 08027658 022658 000008 04 WA 0 0 4 [10] .data PROGBITS 20000000 023000 001398 00 WA 0 0 8 [11] .bss NOBITS 20001398 024398 00f740 00 WA 0 0 8 [12] ._user_heap_stack NOBITS 20010ad8 024398 002000 00 WA 0 0 1 [13] .ARM.attributes ARM_ATTRIBUTES 00000000 024398 000030 00 0 0 1 [14] .comment PROGBITS 00000000 0243c8 000039 01 MS 0 0 1 [15] .debug_info PROGBITS 00000000 024401 1f27e9 00 0 0 1 [16] .debug_abbrev PROGBITS 00000000 216bea 020d3e 00 0 0 1 [17] .debug_aranges PROGBITS 00000000 237928 00cc90 00 0 0 8 [18] .debug_rnglists PROGBITS 00000000 2445b8 009c3c 00 0 0 1 [19] .debug_line PROGBITS 00000000 24e1f4 06ef95 00 0 0 1 [20] .debug_str PROGBITS 00000000 2bd189 1d4157 01 MS 0 0 1 [21] .debug_frame PROGBITS 00000000 4912e0 03a014 00 0 0 4 [22] .debug_line_str PROGBITS 00000000 4cb2f4 0001bc 01 MS 0 0 1 [23] .debug_loclists PROGBITS 00000000 4cb4b0 001e9b 00 0 0 1 [24] .symtab SYMTAB 00000000 4cd34c 00f260 10 25 2637 4 [25] .strtab STRTAB 00000000 4dc5ac 01f90f 00 0 0 1 [26] .shstrtab STRTAB 00000000 4fbebb 00012b 00 0 0 1Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), D (mbind), y (purecode), p (processor specific)There are no section groups in this file.Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08005000 0x08005000 0x22660 0x22660 RWE 0x1000 LOAD 0x023000 0x20000000 0x08027660 0x01398 0x01398 RW 0x1000 LOAD 0x000398 0x20001398 0x20001398 0x00000 0x11740 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .isr_vector .build_info .text .rodata .ARM .init_array .fini_array 01 .data 02 .bss ._user_heap_stackThere is no dynamic section in this file.
It seams that the linker try to align the code to 4kB and not to 2kB.There is a way to force the linker to align the code to 2kB?
The same linkerscript is used to compile FW for a CortexM7 processor, with 2MB of Flash and a different Flash partition, in this case the Flash partition is compatible with 4kB alignment.
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .isr_vector PROGBITS 08040000 001000 0001f8 00 A 0 0 1 [ 2] .build_info PROGBITS 080401f8 0011f8 000098 00 A 0 0 4 [ 3] .text PROGBITS 08040290 001290 0939d8 00 AX 0 0 16 [ 4] .rodata PROGBITS 080d3c68 094c68 025f18 00 A 0 0 8 [ 5] .ARM.extab PROGBITS 080f9b80 0beea0 000000 00 W 0 0 1 [ 6] .ARM ARM_EXIDX 080f9b80 0bab80 000008 00 AL 3 0 4 [ 7] .preinit_array PREINIT_ARRAY 080f9b88 0beea0 000000 04 WA 0 0 1 [ 8] .init_array INIT_ARRAY 080f9b88 0bab88 000070 04 WA 0 0 4 [ 9] .fini_array FINI_ARRAY 080f9bf8 0babf8 000008 04 WA 0 0 4 [10] .data PROGBITS 20000000 0bb000 003ea0 00 WA 0 0 8 [11] .dma NOBITS 20078000 0bf000 0030a0 00 WA 0 0 4 [12] .bss NOBITS 20003ea0 0beea0 03fca0 00 WA 0 0 8 [13] ._user_heap_stack NOBITS 20043b40 0beea0 004800 00 WA 0 0 1 [14] .ARM.attributes ARM_ATTRIBUTES 00000000 0beea0 00002e 00 0 0 1 [15] .comment PROGBITS 00000000 0beece 0000a9 01 MS 0 0 1 [16] .debug_info PROGBITS 00000000 0bef77 b262bd 00 0 0 1 [17] .debug_abbrev PROGBITS 00000000 be5234 063c2c 00 0 0 1 [18] .debug_aranges PROGBITS 00000000 c48e60 02be48 00 0 0 8 [19] .debug_rnglists PROGBITS 00000000 c74ca8 025d1f 00 0 0 1 [20] .debug_line PROGBITS 00000000 c9a9c7 168d5a 00 0 0 1 [21] .debug_str PROGBITS 00000000 e03721 1d9a755 01 MS 0 0 1 [22] .debug_frame PROGBITS 00000000 2b9de78 0ca8ac 00 0 0 4 [23] .debug_line_str PROGBITS 00000000 2c68724 0001c9 01 MS 0 0 1 [24] .debug_loclists PROGBITS 00000000 2c688ed 05e172 00 0 0 1 [25] .debug_loc PROGBITS 00000000 2cc6a5f 0002dd 00 0 0 1 [26] .debug_ranges PROGBITS 00000000 2cc6d3c 000030 00 0 0 1 [27] .symtab SYMTAB 00000000 2cc6d6c 05bbf0 10 28 15989 4 [28] .strtab STRTAB 00000000 2d2295c 240e77 00 0 0 1 [29] .shstrtab STRTAB 00000000 2f637d3 000149 00 0 0 1Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), D (mbind), y (purecode), p (processor specific)There are no section groups in this file.Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0x08040000 0x08040000 0xb9c00 0xb9c00 RWE 0x1000 LOAD 0x0bb000 0x20000000 0x080f9c00 0x03ea0 0x03ea0 RW 0x1000 LOAD 0x000ea0 0x20003ea0 0x20003ea0 0x00000 0x444a0 RW 0x1000 LOAD 0x000000 0x20078000 0x20078000 0x00000 0x030a0 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .isr_vector .build_info .text .rodata .ARM .init_array .fini_array 01 .data 02 .bss ._user_heap_stack 03 .dmaThere is no dynamic section in this file.
The linker script is the following, with a different definition for Cortex M4 or Cortex M7:
INCLUDE "hw_linkerdefs.ld"/* Entry Point */ENTRY(Reset_Handler)/* Highest address of the user mode stack */_estack = _LINKER_StartStack; /* end of RAM *//* Generate a link error if heap and stack don't fit into RAM */_Min_Heap_Size = _LINKER_Min_Heap_Size; /* required amount of heap */_Min_Stack_Size = _LINKER_Min_Stack_Size; /* required amount of stack */_heap_upper_limit = _estack - _LINKER_Min_Stack_Size;_dmaAreaStart = _LINKER_DMA_AREASTART;/* Specify the memory areas *//* ensure consistency to SCB->VTOR defined in system_stm32l4xx.c *//* IMAGETYPE is replaced by cmake into either APP or BOOT*/MEMORY{RAM (xrw) : ORIGIN = _LINKER_RAM_BASEADDR, LENGTH = _LINKER_RAM_SIZEFLASH (rx) : ORIGIN = _LINKER_APP_FLASHSTART, LENGTH = _LINKER_APP_FLASHSIZEFLAGSAREA (r) : ORIGIN = FLAGS_ADDR, LENGTH = 1024 DMARAM (rw) : ORIGIN = _LINKER_DMA_AREASTART, LENGTH = _LINKER_DMA_AREASIZE}/* Define output sections */SECTIONS{ /* The startup code goes first into FLASH */ .isr_vector : { . = ALIGN(8); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(8); } >FLASH /* This is the area reserved for build info */ .build_info : { . = ALIGN(8); KEEP(*(.build_info_index)) *(.build_info_area) . = ALIGN(8); } > FLASH /* The program code and other data goes into FLASH */ .text : { . = ALIGN(8); *(.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(8); _etext = .; /* define a global symbols at end of code */ } >FLASH /* Constant data goes into FLASH */ .rodata : { . = ALIGN(8); KEEP(*(*.uxTopUsedPriority)) *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ . = ALIGN(8); } >FLASH .ARM.extab : { . = ALIGN(8); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(8); } >FLASH .ARM : { . = ALIGN(8); __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; . = ALIGN(8); } >FLASH .preinit_array : { . = ALIGN(8); PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(8); } >FLASH .init_array : { . = ALIGN(8); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(8); } >FLASH .fini_array : { . = ALIGN(8); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(8); } >FLASH /* used by the startup to initialize data */ _sidata = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code */ .data : { . = ALIGN(8); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(8); _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH /* This is only useful for the bootloader build in case it includes the default flags area */ .bootloader_default_flags : { KEEP(*(.bootloader_default_flags)) } > FLAGSAREA /* this rule places the .dma buffers into the DMA area of RAM */ .dma (NOLOAD): { *(.dma) } > DMARAM /* 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 /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : { . = ALIGN(8); PROVIDE ( _end_static_memory = . ); . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(8); } >RAM /* Remove information from the standard libraries */ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } .ARM.attributes 0 : { *(.ARM.attributes) }}
the code is copiled with xpack-arm-none-eabi-gcc-13.3.1-1.1
toolchanin.