From 22cc8d41c8a36cd702ec3012f03873cacc10ab01 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 22 Jul 2026 16:34:48 +0530 Subject: [PATCH] fix(esp_system): fixes build failure with XIP PSRAM + BSS/NoInit in external memory Declare ext_ram_xip_seg as a distinct region overlapping drom_seg at the same origin (the esp32s3/c5/c61/h4 pattern) instead of aliasing drom_seg, so .ext_ram.dummy has its own location counter and .ext_ram.bss reclaims the VMA space of NOLOAD rodata (.rodata_wlog_*), saving up to one MMU page of PSRAM on esp32s31. No layout change on esp32p4. Closes https://github.com/espressif/esp-idf/issues/18791 Related https://github.com/espressif/esp-idf/issues/14992 --- components/esp_system/ld/esp32p4/memory.ld.in | 11 ++++++++++- components/esp_system/ld/esp32s31/memory.ld.in | 11 ++++++++++- components/esp_system/ld/ld.ext_ram.sections | 7 +++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/components/esp_system/ld/esp32p4/memory.ld.in b/components/esp_system/ld/esp32p4/memory.ld.in index e9d1684c689..7195bf36c31 100644 --- a/components/esp_system/ld/esp32p4/memory.ld.in +++ b/components/esp_system/ld/esp32p4/memory.ld.in @@ -163,6 +163,15 @@ MEMORY /* PSRAM seg */ extern_ram_seg(RWX) : org = 0x48000000, len = IDROM_SEG_SIZE + +#if CONFIG_SPIRAM_XIP_FROM_PSRAM + /** + * Distinct region overlapping `drom_seg` at the same origin, so `.ext_ram.dummy` + * gets its own location counter and `.ext_ram.bss` can reclaim the space of + * NOLOAD rodata (e.g. `.rodata_wlog_*`). + */ + ext_ram_xip_seg(RWX) : org = 0x48000020, len = IDROM_SEG_SIZE - 0x20 +#endif // CONFIG_SPIRAM_XIP_FROM_PSRAM } /* Heap ends at top of dram0_0_seg */ @@ -212,7 +221,7 @@ REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg ); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS #if CONFIG_SPIRAM_XIP_FROM_PSRAM - REGION_ALIAS("ext_ram_seg", drom_seg); + REGION_ALIAS("ext_ram_seg", ext_ram_xip_seg); #else REGION_ALIAS("ext_ram_seg", extern_ram_seg); #endif //#if CONFIG_SPIRAM_XIP_FROM_PSRAM diff --git a/components/esp_system/ld/esp32s31/memory.ld.in b/components/esp_system/ld/esp32s31/memory.ld.in index 5c472a46a77..666eca55342 100644 --- a/components/esp_system/ld/esp32s31/memory.ld.in +++ b/components/esp_system/ld/esp32s31/memory.ld.in @@ -85,6 +85,15 @@ MEMORY /* PSRAM seg */ extern_ram_seg(RWX) : org = 0x50000000, len = IDROM_SEG_SIZE + +#if CONFIG_SPIRAM_XIP_FROM_PSRAM + /** + * Distinct region overlapping `drom_seg` at the same origin, so `.ext_ram.dummy` + * gets its own location counter and `.ext_ram.bss` can reclaim the space of + * NOLOAD rodata (e.g. `.rodata_wlog_*`). + */ + ext_ram_xip_seg(RWX) : org = 0x50000020, len = IDROM_SEG_SIZE - 0x20 +#endif // CONFIG_SPIRAM_XIP_FROM_PSRAM } /* Heap ends at top of dram0_0_seg */ @@ -114,7 +123,7 @@ REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS #if CONFIG_SPIRAM_XIP_FROM_PSRAM - REGION_ALIAS("ext_ram_seg", drom_seg); + REGION_ALIAS("ext_ram_seg", ext_ram_xip_seg); #else REGION_ALIAS("ext_ram_seg", extern_ram_seg); #endif //#if CONFIG_SPIRAM_XIP_FROM_PSRAM diff --git a/components/esp_system/ld/ld.ext_ram.sections b/components/esp_system/ld/ld.ext_ram.sections index b214e5915b3..434cc259d85 100644 --- a/components/esp_system/ld/ld.ext_ram.sections +++ b/components/esp_system/ld/ld.ext_ram.sections @@ -9,6 +9,13 @@ .ext_ram.dummy (NOLOAD) : { HIDDEN(_ext_ram_on_same_bus = ORIGIN(ext_ram_seg) == ORIGIN(flash_rodata_seg)); + /** + * This must be the first section placed in `ext_ram_seg`, and `ext_ram_seg` must be + * a distinct region (not a REGION_ALIAS of `flash_rodata_seg`) so it has its own + * location counter. Otherwise NOLOAD rodata (e.g. .rodata_wlog_*) placed after + * `_rodata_reserved_end` leaves the counter past the skip target, and moving it + * backwards here is a hard linker error. + */ . = _ext_ram_on_same_bus ? ORIGIN(ext_ram_seg) + (_rodata_reserved_end - _flash_rodata_dummy_start) : 0; . = ALIGN(_ext_ram_on_same_bus ? _esp_mmu_page_size : 0); } > ext_ram_seg