Skip to content

fix(linker): correct cross-toolchain memory map inconsistencies - #21

Open
94xhn wants to merge 2 commits into
STMicroelectronics:mainfrom
94xhn:fix/linker-cross-toolchain-audit
Open

fix(linker): correct cross-toolchain memory map inconsistencies#21
94xhn wants to merge 2 commits into
STMicroelectronics:mainfrom
94xhn:fix/linker-cross-toolchain-audit

Conversation

@94xhn

@94xhn 94xhn commented Jul 11, 2026

Copy link
Copy Markdown

Summary

I cross-checked the GCC (STM32CubeIDE/*.ld), IAR (EWARM/*.icf) and Keil (MDK-ARM/*.uvprojx -> real .sct scatter file, not the stale OCR_RVCT* XML placeholders) linker descriptions of the same physical memory for every example under Projects/, and found 4 GCC-only drifts across 8 linker scripts, each confirmed by IAR and Keil independently agreeing with each other and disagreeing with GCC.

1. RAM/ROM overlap — PWR_STANDBY / PWR_STANDBY_RTC (STM32N6570-DK, Appli role)

Projects/STM32N6570-DK/Examples/PWR/PWR_STANDBY/STM32CubeIDE/Appli/STM32N657X0HXQ_LRUN.ld and the _RTC sibling declared:

ROM (xrw) : ORIGIN = 0x34000400, LENGTH = 511K   // ends at 0x3407FFFF
RAM (xrw) : ORIGIN = 0x34020000, LENGTH = 1536K  // starts INSIDE the ROM region

RAM starts at 0x34020000, which is 384 KB before ROM ends (0x3407FFFF), so the two regions overlap by 384 KB — code/rodata placed near the end of ROM would share physical bytes with .data/.bss.

Both EWARM/Appli/stm32n657xx_LRUN.icf (__ICFEDIT_region_RAM_start__ = 0x34080000) and MDK-ARM/Appli/stm32n657xx_LRUN.sct (__RAM_BASE 0x34080000) start RAM immediately after ROM ends, with no overlap. Fixed GCC's RAM origin to 0x34080000 in both examples.

2. RAM under-allocated by 128 KB — CORTEX_InterruptSwitch_TrustZone (NUCLEO-N657X0-Q, AppliNonSecure role)

Projects/NUCLEO-N657X0-Q/Examples/CORTEX/CORTEX_InterruptSwitch_TrustZone/STM32CubeIDE/AppliNonSecure/STM32N657X0HXQ_FLASH.ld declared a single merged RAM (xrw): ORIGIN = 0x241a0000, LENGTH = 256K (0x241a0000-0x241DFFFF).

EWARM/AppliNonSecure/stm32n657xx_fsbl_ns.icf defines ROM_region (0x241A0000-0x241BFFFF, 128K) + RAM_region (0x241C0000-0x241FFFFF, 256K) = 384K total, and MDK-ARM/AppliNonSecure/stm32n657xx_ns.sct agrees (__ROM_SIZE 0x20000 + __RAM_SIZE 0x40000 = 384K). Both independently authored toolchain files put the usable non-secure window's top at 0x241FFFFF, which also matches the well-established top of the same physical AXISRAM2 bank used identically (secure alias 0x341FFFFF) across dozens of other examples in the repo. GCC's file stopped 128 KB short of that boundary with nothing else claiming the missing space. Widened GCC's RAM LENGTH from 256K to 384K (origin unchanged) to reclaim the missing 128 KB and match both other toolchains.

3. FSBL RAM off-by-1KB — VENC_RTSP_Server / VENC_SDCard / VENC_SDCard_ThreadX / VENC_USB (STM32N6570-DK, FSBL role)

All four STM32CubeIDE/FSBL/STM32N657XX_AXISRAM2_fsbl.ld files declared:

ROM (xr) : ORIGIN = 0x34180400, LENGTH = 255K
RAM (rw) : ORIGIN = 0x341C0000, LENGTH = 255K   // should be 256K

RAM at LENGTH = 255K looks like the ROM line's 255K was copy-pasted down. Both EWARM/FSBL/stm32n657xx_axisram2_fsbl.icf (__ICFEDIT_region_RAM_end__ = 0x341FFFFF, i.e. 256K) and MDK-ARM/FSBL/stm32n657xx_axisram2_fsbl.sct (__RAM_SIZE 0x00040000 = 256K) agree the region is a full 256K. Fixed all four to LENGTH = 256K.

4. Appli ROM off-by-1KB — VENC_SDCard (STM32N6570-DK, Appli role)

Projects/STM32N6570-DK/Applications/VENC/VENC_SDCard/STM32CubeIDE/Appli/STM32N657XX_LRUN.ld declared ROM (xr) : ORIGIN = 0x34000400, LENGTH = 256K, one KB larger than EWARM/Appli/stm32n657xx_LRUN.icf (__ICFEDIT_region_ROM_end__ = 0x3403FFFF -> 255K) and MDK-ARM/Appli/stm32n657xx_LRUN.sct (__ROM_SIZE 0x0003FC00 -> 255K). This is inconsistent with the convention used everywhere else in the repo, where a ROM window starting at a +0x400 header offset is sized (bank − 1K). Fixed GCC's ROM LENGTH from 256K to 255K.

Notes on false positives excluded

While auditing I found several automated size mismatches that turned out not to be bugs after reading the actual SECTIONS/scatter placement, and excluded them:

  • Several NetXDuo (Nx_*) FSBL examples: GCC keeps one monolithic RAM region and places the NetX packet pool at an absolute address inside it, while IAR carves out a separate named region (NXApp_region) at the exact same address — same physical layout, different linker-script idiom.
  • Template_FSBL_LRUN / Template_Isolation_LRUN/_XIP FSBL/Appli roles: GCC merges ROM+RAM into one named region whose size equals the split IAR/Keil totals exactly — again a stylistic difference, not a drift.
  • ITCM 128K vs 64K in several VENC_* Appli GCC scripts: the ITCM MEMORY entry is declared but never referenced in SECTIONS, so it's dead/unused and carries no functional risk; left untouched.
  • One region (RAM in CORTEX_InterruptSwitch_TrustZone's FSBL role, secure side) where GCC and Keil agree with each other and only IAR differs by 4x — inconclusive without a datasheet cross-check, so left unchanged rather than guess.

Test plan

No local ARM toolchain (armclang/armcc/IAR) available, so verification was done purely via address arithmetic:

  • Recomputed ORIGIN/LENGTH -> end-address for every changed region and confirmed no more overlap with sibling regions in the same file (issue 1).
  • Confirmed the new GCC region boundaries land exactly on the addresses independently declared by both EWARM/*.icf and MDK-ARM/*.sct for the same example/role (issues 1-4).
  • Cross-checked the corrected boundaries against the physical AXISRAM2 bank top (0x241FFFFF/0x341FFFFF) used consistently across the rest of Projects/ (issue 2).
  • Grepped the whole repo for each buggy pattern to make sure every affected file was found and fixed (issue 3: exactly 4 files; issue 4: 1 file).

Disclosure

This audit and patch were prepared with Claude (Anthropic) assistance — automated cross-toolchain diffing to surface candidate mismatches, with every flagged case then manually re-verified by hand (reading the actual SECTIONS/scatter-file placement, computing region boundaries, and cross-referencing all three toolchains) before deciding whether to fix it. All changes have been reviewed by me before submission.

…M32N6 GCC linker scripts

Cross-checked the GCC (STM32CubeIDE .ld), IAR (EWARM .icf) and Keil
(MDK-ARM .sct, the real scatter file referenced by <ScatterFile> in
.uvprojx, not the stale OCR_RVCT placeholders) linker descriptions of
the same physical memory for every Projects/* example and found four
GCC-only drifts, all confirmed by both other toolchains agreeing with
each other and disagreeing with GCC:

1. PWR_STANDBY / PWR_STANDBY_RTC (STM32N6570-DK, Appli role): the GCC
   RAM region started at 0x34020000 while ROM (511K @ 0x34000400) ends
   at 0x3407FFFF, so RAM overlapped the last 384 KB of ROM. IAR and
   Keil both start RAM at 0x34080000 (immediately after ROM). Moved
   the GCC RAM origin to 0x34080000 to remove the overlap.

2. CORTEX_InterruptSwitch_TrustZone (NUCLEO-N657X0-Q, AppliNonSecure
   role): GCC declared only 256 KB of non-secure RAM (0x241A0000-
   0x241DFFFF) while IAR (ROM_region + RAM_region) and Keil
   (ROM_SIZE + RAM_SIZE) both cover the full 384 KB non-secure window
   up to 0x241FFFFF, which is also the well-established top of that
   AXISRAM2 bank used consistently across the rest of the repository
   (secure alias 0x341FFFFF). Widened GCC's RAM LENGTH from 256K to
   384K to match.

3. VENC_RTSP_Server / VENC_SDCard / VENC_SDCard_ThreadX / VENC_USB
   (STM32N6570-DK, FSBL role): GCC declared the FSBL RAM region as
   255K instead of 256K (looks like the adjacent ROM line's 255K was
   copy-pasted into the RAM line). Both IAR (__ICFEDIT_region_RAM_end__
   = 0x341FFFFF) and Keil (__RAM_SIZE = 0x00040000) agree the region
   is the full 256K. Fixed GCC RAM LENGTH from 255K to 256K in all
   four FSBL linker scripts.

4. VENC_SDCard (STM32N6570-DK, Appli role): the same project's ROM
   region was declared as a round 256K, one KB larger than IAR
   (__ICFEDIT_region_ROM_end__ = 0x3403FFFF -> 255K) and Keil
   (__ROM_SIZE = 0x0003FC00 -> 255K), inconsistent with the repo-wide
   convention that a ROM window starting at a +0x400 header offset is
   sized (bank - 1K). Fixed GCC ROM LENGTH from 256K to 255K.

No local ARM toolchain available; verified purely via address
arithmetic (region overlap / boundary matching) cross-referenced
against the independently-authored IAR and Keil files for the same
example.

Several other automated mismatches were investigated and excluded as
false positives, e.g. GCC merging ROM+RAM into a single named region
where IAR/Keil split them (same total physical span, just a different
MEMORY block style), and NetXDuo examples where GCC uses an absolute-
address sub-section for the packet pool while IAR carves out a
separate named region at the same address (same physical layout,
different linker-script idiom).

Signed-off-by: 94xhn <87560781+94xhn@users.noreply.github.com>
@ALABSTM ALABSTM added bug Something isn't working projects Projects-related (demos, applications, examples) issue or pull-request. labels Jul 13, 2026
@ALABSTM ALABSTM assigned ALABSTM and unassigned MKISTM Jul 17, 2026

@ALABSTM ALABSTM left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @94xhn,

Thank you for this other thorough review of our linker files. I have a few questions I have to loop back about with our development team. I'll let you know so you can update your pull request accordingly.

Meanwhile, please do not hesitate if you would like to reply to my remarks.

With regards,

{
ROM (xrw) : ORIGIN = 0x34000400, LENGTH = 511K
RAM (xrw) : ORIGIN = 0x34020000, LENGTH = 1536K
RAM (xrw) : ORIGIN = 0x34080000, LENGTH = 1536K

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also questioning the length of this memory area in secure AXISRAM1. 1536kB in decimal translate to 0x0018'0000B in hexadecimal, making this region extend till address 0x341F'FFFF.

This overlaps with the FSBL in secure AXISRAM2, starting at address 0x3418'0000 according to the REAMD.md (see below), assuming both memories are contiguous. Does it not?

According to Table 2. Memory map and peripheral register boundary addresses of RM0486, rev. 4, the secure AXISRAM1 region ends at address 0x340F'FFFF. This would leave only 512kB room for the RAM region.

- The FSBL project runs in AXISRAM2 (0x3418'0000) and is executed upon power-on after bootROM execution.
- The application is loaded into AXISRAM1 (0x3400'0000) and executed after the FSBL.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ALABSTM, you were right here. I rechecked the example-specific MDK scatter file and the RAM window for this PWR application is 0x34080000-0x340FFFFF, not 1536KB up to 0x341FFFFF. I have now updated both GCC and IAR for PWR_STANDBY and PWR_STANDBY_RTC to the same 512KB range, which also removes the overlap with the FSBL in AXISRAM2.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @94xhn,

I built the Appli subproject of the PWR_STANDBY example using STM32CubeIDE 2.1.1 and, based on the log, the footprint of the different sections to be located into the RAM region is just a "handful" of bytes, confirming the 512kB length fix.

arm-none-eabi-objcopy  -O binary PWR_STANDBY_Appli.elf  "PWR_STANDBY_Appli.bin"
   text	   data	    bss	    dec	    hex	filename
  14312	     32	   2592	  16936	   4228	PWR_STANDBY_Appli.elf
Finished building: default.size.stdout

With regards,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for checking it with STM32CubeIDE and for the approval. That build result is useful confirmation of the corrected RAM range.

{
ROM (xrw) : ORIGIN = 0x34000400, LENGTH = 511K
RAM (xrw) : ORIGIN = 0x34020000, LENGTH = 1536K
RAM (xrw) : ORIGIN = 0x34080000, LENGTH = 1536K

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same remark about the RAM region's length.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied the same correction to the RTC sibling as well: GCC and IAR now both use RAM 0x34080000-0x340FFFFF, matching the MDK scatter file there too.

MEMORY
{
RAM (xrw) : ORIGIN = 0x241a0000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x241a0000, LENGTH = 384K

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange that the memory is not split between ROM and RAM as done for the two other IDEs. It is the case in a similar application, as shown below.

ROM (xrw) : ORIGIN = 0x24100400, LENGTH = 511K
RAM (xrw) : ORIGIN = 0x24180000, LENGTH = 512K

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I aligned the GCC script with that split now. The non-secure window is defined as ROM 0x241A0000-0x241BFFFF plus RAM 0x241C0000-0x241FFFFF, matching the example's IAR file, MDK scatter file, and README.

@github-project-automation github-project-automation Bot moved this from To do to In progress in stm32cube-mcu-fw-dashboard Jul 27, 2026
The PWR standby application windows were rechecked against the example-specific MDK scatter files after the review feedback. The earlier 1536K assumption was wrong, so both PWR_STANDBY variants now keep the corrected 0x34080000 RAM origin but stop at 0x340FFFFF in GCC and IAR.

The non-secure GCC linker script for CORTEX_InterruptSwitch_TrustZone now also uses the same ROM/RAM split already defined by the example's IAR and MDK files instead of one merged 384K RAM region.

Constraint: No local ARM, IAR, or Keil linkers available; verification had to be static interval checks against repo linker metadata
Rejected: Keep 1536K and argue AXISRAM2 reuse | The example-specific MDK scatter limits the same PWR application RAM to 512K, so the earlier assumption was incorrect
Confidence: high
Scope-risk: narrow
Directive: For STM32N6 FSBL plus application examples, do not generalize from Template_FSBL_LRUN alone; cross-check the example-specific MDK scatter and security or retention map first
Tested: Node-based interval checks for PWR_STANDBY, PWR_STANDBY_RTC, and CORTEX_InterruptSwitch_TrustZone across GCC, IAR, and MDK; git diff --check
Not-tested: Local ARM, IAR, or Keil link-load; hardware boot or wakeup
@94xhn

94xhn commented Jul 28, 2026

Copy link
Copy Markdown
Author

Hi @ALABSTM, I pushed commit d7bdc94 addressing the three review points.\n\n- PWR_STANDBY and PWR_STANDBY_RTC: GCC and IAR now use RAM 0x34080000-0x340FFFFF, after rechecking the example-specific MDK scatter files.\n- CORTEX_InterruptSwitch_TrustZone AppliNonSecure: the GCC linker script now uses the same ROM/RAM split as the example's IAR and MDK files.\n\nVerification was done by recomputing the start/end addresses from the updated GCC, IAR, and MDK linker descriptions and confirming the three toolchains now agree for each reviewed example.

@ALABSTM ALABSTM left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @94xhn,

Thank you very much for your prompt reply and these updates. Approved.

With regards,

@ALABSTM

ALABSTM commented Jul 28, 2026

Copy link
Copy Markdown

ST Internal Reference: 38e6a5aa83920710b42ee9402fda1ed7

@ALABSTM ALABSTM added the internal bug tracker Issue confirmed and reported into a ticket in the internal bug tracking system label Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working internal bug tracker Issue confirmed and reported into a ticket in the internal bug tracking system projects Projects-related (demos, applications, examples) issue or pull-request.

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

3 participants