Skip to content

Feat/improve linker scripts - #640

Open
FoniksFox wants to merge 26 commits into
developmentfrom
feat/Improve-Linker-Scripts
Open

Feat/improve linker scripts#640
FoniksFox wants to merge 26 commits into
developmentfrom
feat/Improve-Linker-Scripts

Conversation

@FoniksFox

@FoniksFox FoniksFox commented May 4, 2026

Copy link
Copy Markdown
Contributor

Closes #625
Closes #653
Closes #658

A refactor of the Linker Script, Startup Code and System.c

Check the corresponding pr in the template-project to see the changes needed to make it work.

It implementes:

  • Initialized data sections for all memory domains with a copy table, so that ResetHandler can generally copy all data defined in the table.
  • A Linker Script with configurable ITCM memory via macros (C preprocessor) and the possibility to add all code to ITCM.
  • ISR vector always copied to ITCM.
  • Implement DTCM constants.
  • weak BoardInit function that gets called after SystemInit, but before global constructors

Not implemented left as a weak definition so that users can implement their own version):

  • Configuration checker (a function to check whether the provided ITCM size matches the defined size, and whatever other configuration that's deemed as necessary)

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

ST-LIB Release Plan

  • Current version: 6.3.1
  • Pending changesets: 1
  • Highest requested bump: major
  • Next version if merged now: 7.0.0

Pending changes

  • major Refactor linker script, startup code, and memory model with unified copy/zero tables, configurable ITCM, and weak BoardInit. Also fixes LTO. (.changesets/refactor-linker-script.md)

@FoniksFox
FoniksFox marked this pull request as ready for review June 1, 2026 22:10
Copilot AI lite review requested due to automatic review settings August 4, 2026 15:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors the STM32H723 startup/linker infrastructure in ST-LIB to support a table-driven startup initialization (copy/zero tables), configurable ITCM usage, and updated MPU/sectioning conventions to better support multi-memory-domain placement and initialization.

Changes:

  • Introduces a unified LinkerScript.ld with copy/zero tables, ITCM configuration macros, and expanded D1/D2/D3 cached/non-cached section layout.
  • Updates StartupCode.s to use the copy/zero tables and call a weak BoardInit() hook during early startup.
  • Updates MPU section macros and several drivers to use the new per-domain/per-type linker sections.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
System.c Adds system initialization implementation plus weak ConfigurationChecker() / BoardInit() hooks for early boot.
StartupCode.s Switches Reset_Handler to table-driven copy/zero init and adds BoardInit call + VTOR relocation logic.
LinkerScript.ld New unified linker script supporting ITCM configuration and copy/zero tables across all memory domains.
Src/HALAL/Services/EXTI/EXTI.cpp Removes a file header comment block (no functional change).
Src/HALAL/Models/TimerDomain/TimerDomain.cpp Adds the new input_capture_info_dummy definition as a proper static member.
Inc/HALAL/Models/TimerDomain/TimerDomain.hpp Moves input_capture_info_dummy from a header-global to a TimerDomain static member declaration.
Src/HALAL/Models/MPUManager/MPUManager.cpp Updates legacy MPUManager pool section name to match the new linker script.
Inc/HALAL/Models/MPU.hpp Overhauls MPU placement macros, updates linker symbol names, fixes as()/construct() constexpr access, adds null-pointer guard region.
Inc/HALAL/Services/ADC/ADC.hpp Moves ADC DMA buffer placement to the new D2 non-cached BSS inline section pattern.
Inc/HALAL/Services/DFSDM/DFSDM.hpp Moves DFSDM DMA buffers to the new D2 non-cached BSS inline section pattern.
Inc/HALAL/Models/SPI/SPI2.hpp Adjusts static inline array definition form for instances.
Inc/ST-LIB.hpp Declares extern "C" void BoardInit(void); for user override from C++ firmware.
Inc/MockedDrivers/stm32h7xx_hal_mock.h Adds MPU_REGION_NUMBER12 needed for the new null-guard MPU region.
CMakeLists.txt Ensures System.c is built for cross-compiling targets; adjusts LTO enabling via compile flags.
.changesets/refactor-linker-script.md Adds a major-release changeset documenting the startup/linker/MPU refactor and migration notes.
Suppressed comments (1)

StartupCode.s:24

  • VTOR is updated to the ITCM vector table before the copy-table runs. If any exception occurs during ConfigurationChecker, SystemInit, or the copy loop (e.g., HardFault), the CPU will fetch vectors from ITCM before they have been copied, which can make faults un-debuggable or cascade. Consider delaying the VTOR update until after the copy-table has copied .isr_vector into ITCM (first copy-table entry), e.g., keep VTOR at the default/Flash vector during early boot and set it right after .L_done_copy_table:.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread LinkerScript.ld Outdated
Comment thread System.c Outdated
@@ -0,0 +1,191 @@
#define BOOT_ATTR __attribute__((section(".boot"))) __used
Copilot AI review requested due to automatic review settings August 4, 2026 17:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Suppressed comments (8)

System.c:1

  • BOOT_ATTR places SystemInit/SystemCoreClockUpdate/ConfigurationChecker into an input section named ".boot", but the linker script only keeps ".boot_code*" inside the FLASH-only boot output section. This can make SystemInit land in an orphan section (potentially in ITCM when __ITCM_BUILD is enabled), which is unsafe because Reset_Handler calls SystemInit before the copy-table has initialized RAM/ITCM.
#define BOOT_ATTR __attribute__((section(".boot"))) __used

StartupCode.s:24

  • Reset_Handler sets VTOR to the ITCM vector table before the copy-table loop has copied .isr_vector from FLASH into ITCM. If any exception occurs during ConfigurationChecker/SystemInit or during the copy loop (e.g., HardFault), the CPU will fetch vectors from partially-copied/uninitialized ITCM, which can make debugging and recovery unreliable. Consider keeping VTOR pointing at the FLASH vector table initially, and only switching VTOR after the vector table copy entry has completed.
    LinkerScript.ld:339
  • Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d1_data/__d1_end are captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into subsequent memory. Align to 4 bytes before capturing these end symbols.
    . = ALIGN(32);
    __sram_d1_data = ABSOLUTE(.);

    *(.ram_d1.user.data)
    *(.ram_d1.user.data*)
    *(.ram_d1.user.rodata)
    *(.ram_d1.user.rodata*)
    BYTE(0);

LinkerScript.ld:375

  • Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d2_nc_data is captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into padding/next region. Align to 4 bytes before capturing the end symbol.
  {
    . = ALIGN(32);
    __sram_d2_nc_data = ABSOLUTE(.);

    *(.ram_d2_nc.user.data)
    *(.ram_d2_nc.user.data*)
    *(.ram_d2_nc.user.rodata)
    *(.ram_d2_nc.user.rodata*)

LinkerScript.ld:420

  • Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d2_data/__d2_end are captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into subsequent memory. Align to 4 bytes before capturing these end symbols.
  } >RAM_D2
  .ram_d2_data_rodata :
  {
    . = ALIGN(32);
    __sram_d2_data = ABSOLUTE(.);

    *(.ram_d2.user.data)
    *(.ram_d2.user.data*)
    *(.ram_d2.user.rodata)

LinkerScript.ld:453

  • Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d3_nc_data is captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into padding/next region. Align to 4 bytes before capturing the end symbol.
    *(.ram_d3_nc.user.bss)
    *(.ram_d3_nc.user.bss*)
    __eram_d3_nc_bss = ABSOLUTE(.);
  } >RAM_D3
  .ram_d3_nc_data_rodata :
  {
    . = ALIGN(32);
    __sram_d3_nc_data = ABSOLUTE(.);

LinkerScript.ld:498

  • Same copy-table word-copy alignment issue here: BYTE(0) is added, but __eram_d3_data/__d3_end are captured without re-aligning to 4 bytes. Since Reset_Handler copies 4 bytes at a time, this can overrun into subsequent memory. Align to 4 bytes before capturing these end symbols.
    . = ALIGN(32);
    *(.ram_d3.user.bss)
    *(.ram_d3.user.bss*)

    __eram_d3_bss = ABSOLUTE(.);
  } >RAM_D3
  .ram_d3_data_rodata :
  {
    . = ALIGN(32);

LinkerScript.ld:483

  • This section list includes a duplicated input-section pattern: *(.ram_d3.user.bss) is already included above, and is repeated again after *(.ram_d3.buffer). The second occurrence is redundant and makes it harder to see what is intended to be placed in the D3 cached region.
  PROVIDE(_ram_d3_nc_end = __d3_nc_end);

  /* MPU D3 Cached Section */
  .ram_d3_bss (NOLOAD) :
  {
    . = ALIGN(32);
    __d3_start = ABSOLUTE(.);
    __sram_d3_bss = ABSOLUTE(.);

Comment thread LinkerScript.ld
Comment on lines +288 to +292
*(.ram_d1_nc.user.rodata)
*(.ram_d1_nc.user.rodata*)
BYTE(0);

__eram_d1_nc_data = ABSOLUTE(.);
Copilot AI review requested due to automatic review settings August 4, 2026 17:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Suppressed comments (11)

System.c:1

  • BOOT_ATTR expands to an undefined token __used, which will fail to compile. Also, the section name .boot is not explicitly collected by LinkerScript.ld (it collects .boot_code*), so these functions can become orphan sections with unpredictable placement when --gc-sections is enabled.
#define BOOT_ATTR __attribute__((section(".boot"))) __used

StartupCode.s:25

  • VTOR is set to __sisr_vector before the copy-table runs, so any early exception (HardFault/NMI, etc.) will vector through an uninitialized table in ITCM. VTOR should remain pointing at the Flash vector table until after .isr_vector has been copied.

This issue also appears on line 47 of the same file.
StartupCode.s:48

  • After the copy-table finishes, VTOR should be switched to the relocated vector table address in ITCM now that the copy has completed.
    StartupCode.s:27
  • Calling ConfigurationChecker before the copy/zero tables run makes user overrides unsafe when __ITCM_BUILD=1 (the override will likely live in .text/ITCM and hasn’t been copied yet). Call it after memory initialization instead.

This issue also appears on line 65 of the same file.
StartupCode.s:67

  • ConfigurationChecker should run after the copy/zero tables so it can safely access initialized data (and so user overrides work when .text is relocated).
    LinkerScript.ld:292
  • This output section appends BYTE(0); but does not realign the location counter before exporting __eram_d1_nc_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
    *(.ram_d1_nc.user.rodata)
    *(.ram_d1_nc.user.rodata*)
    BYTE(0);

    __eram_d1_nc_data = ABSOLUTE(.);

LinkerScript.ld:341

  • This output section appends BYTE(0); but does not realign the location counter before exporting __eram_d1_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
    *(.ram_d1.user.rodata)
    *(.ram_d1.user.rodata*)
    BYTE(0);

    __eram_d1_data = ABSOLUTE(.);

LinkerScript.ld:378

  • This output section appends BYTE(0); but does not realign the location counter before exporting __eram_d2_nc_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
    *(.ram_d2_nc.user.rodata)
    *(.ram_d2_nc.user.rodata*)
    BYTE(0);

    __eram_d2_nc_data = ABSOLUTE(.);

LinkerScript.ld:424

  • This output section appends BYTE(0); but does not realign the location counter before exporting __eram_d2_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
    *(.ram_d2.user.rodata)
    *(.ram_d2.user.rodata*)
    BYTE(0);

    __eram_d2_data = ABSOLUTE(.);

LinkerScript.ld:461

  • This output section appends BYTE(0); but does not realign the location counter before exporting __eram_d3_nc_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
    *(.ram_d3_nc.user.rodata)
    *(.ram_d3_nc.user.rodata*)
    BYTE(0);

    __eram_d3_nc_data = ABSOLUTE(.);

LinkerScript.ld:507

  • This output section appends BYTE(0); but does not realign the location counter before exporting __eram_d3_data. Since Reset_Handler copies in 32-bit words, a non-4-byte-aligned end address can cause a 1–3 byte overrun into the next region.
    *(.ram_d3.user.rodata)
    *(.ram_d3.user.rodata*)
    BYTE(0);

    __eram_d3_data = ABSOLUTE(.);

Copilot AI review requested due to automatic review settings August 4, 2026 17:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants