From dfafd6fc2a7d8dca21739d6543b3e86f1ee95367 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 28 Jan 2026 18:57:27 +0700 Subject: [PATCH] fix(esp_system): xtensa: refactor linker scripts and reduce binary size for C++ apps --- components/esp_system/ld/esp32/memory.ld.in | 3 - components/esp_system/ld/esp32/sections.ld.in | 96 +++++++++++------- components/esp_system/ld/esp32s2/memory.ld.in | 2 - .../esp_system/ld/esp32s2/sections.ld.in | 92 ++++++++++------- components/esp_system/ld/esp32s3/memory.ld.in | 3 - .../esp_system/ld/esp32s3/sections.ld.in | 99 +++++++++++-------- components/esp_system/ld/ld.common | 5 + .../portable/xtensa/port.c | 40 ++++---- .../FreeRTOS-Kernel/portable/xtensa/port.c | 40 ++++---- 9 files changed, 225 insertions(+), 155 deletions(-) diff --git a/components/esp_system/ld/esp32/memory.ld.in b/components/esp_system/ld/esp32/memory.ld.in index df13722b0c..66071e3d13 100644 --- a/components/esp_system/ld/esp32/memory.ld.in +++ b/components/esp_system/ld/esp32/memory.ld.in @@ -141,9 +141,6 @@ _heap_end = ALIGN(0x40000000 - _sram1_iram_len - 3, 4); _heap_end = 0x40000000 - CONFIG_ESP32_TRACEMEM_RESERVE_DRAM; #endif - -_data_seg_org = ORIGIN(rtc_data_seg); - /* The lines below define location alias for .rtc.data section based on Kconfig option. When the option is not defined then use slow memory segment else the data will be placed in fast memory segment */ diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index fd13d6afd8..5dfa4c37fb 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -19,7 +19,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_text_start) - mapping[rtc_text] + SECTION_MAPPINGS(rtc_text) *rtc_wake_stub*.*(.literal .text .literal.* .text.*) @@ -49,7 +49,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_force_fast_start) - mapping[rtc_force_fast] + SECTION_MAPPINGS(rtc_force_fast) *(.rtc.force_fast .rtc.force_fast.*) @@ -68,7 +68,7 @@ SECTIONS { _rtc_data_start = ABSOLUTE(.); - mapping[rtc_data] + SECTION_MAPPINGS(rtc_data) *rtc_wake_stub*.*(.data .rodata .data.* .rodata.*) @@ -83,7 +83,7 @@ SECTIONS *rtc_wake_stub*.*(.bss .bss.*) *rtc_wake_stub*.*(COMMON) - mapping[rtc_bss] + SECTION_MAPPINGS(rtc_bss) _rtc_bss_end = ABSOLUTE(.); } > rtc_data_location @@ -100,6 +100,8 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_noinit_start) + SECTION_MAPPINGS(rtc_noinit) + *(.rtc_noinit .rtc_noinit.*) ALIGNED_SYMBOL(4, _rtc_noinit_end) @@ -222,8 +224,7 @@ SECTIONS /* Code marked as running out of IRAM */ _iram_text_start = ABSOLUTE(.); - mapping[iram0_text] - + SECTION_MAPPINGS(iram0_text) } > iram0_0_seg .dram0.data : @@ -237,7 +238,7 @@ SECTIONS *(.gnu.linkonce.s2.*) *(.jcr) - mapping[dram0_data] + SECTION_MAPPINGS(dram0_data) _data_end = ABSOLUTE(.); } > dram0_0_seg @@ -250,6 +251,7 @@ SECTIONS { _ext_ram_noinit_start = ABSOLUTE(.); + SECTION_MAPPINGS(extram_noinit) *(.ext_ram_noinit*) ALIGNED_SYMBOL(4, _ext_ram_noinit_end) @@ -275,7 +277,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _ext_ram_bss_start) - mapping[extern_ram] + SECTION_MAPPINGS(extern_ram) ALIGNED_SYMBOL(4, _ext_ram_bss_end) } > extern_ram_seg @@ -285,11 +287,7 @@ SECTIONS { ALIGNED_SYMBOL(8, _bss_start) - /** - * ldgen places all bss-related data to mapping[dram0_bss] - * (See components/esp_system/app.lf). - */ - mapping[dram0_bss] + SECTION_MAPPINGS(dram0_bss) ALIGNED_SYMBOL(8, _bss_end) } > dram0_0_seg @@ -326,7 +324,7 @@ SECTIONS { _flash_rodata_start = ABSOLUTE(.); - mapping[flash_rodata] + SECTION_MAPPINGS(flash_rodata) *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) @@ -344,16 +342,6 @@ SECTIONS __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); *(.xt_except_desc_end) -#if EH_FRAME_LINKING_ENABLED - ALIGNED_SYMBOL(4, __eh_frame) - KEEP(*(.eh_frame)) - /** - * As we are not linking with crtend.o, which includes the CIE terminator - * (see __FRAME_END__ in libgcc sources), it is manually provided here. - */ - LONG(0); -#endif // EH_FRAME_LINKING_ENABLED - /** * C++ constructor tables. * @@ -381,9 +369,37 @@ SECTIONS *(.lit4.*) *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(SECTION_AFTER_FLASH_RODATA)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.rodata, SECTION_AFTER_FLASH_RODATA) - /* TLS data. */ - ALIGNED_SYMBOL(4, _thread_local_start) +#if EH_FRAME_LINKING_ENABLED + .eh_frame : + { + ALIGNED_SYMBOL(4, __eh_frame) + + KEEP (*(.eh_frame)) + /** + * As we are not linking with crtend.o, which includes the CIE terminator + * (see __FRAME_END__ in libgcc sources), it is manually provided here. + */ + LONG(0); + + __eh_frame_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.tdata)); + } > default_rodata_seg +#endif // EH_FRAME_LINKING_ENABLED + + .flash.tdata : + { + /* Keep tdata and tbss sections contiguous (no gaps between them). + * The TLS runtime code calculates offsets assuming these sections are + * adjacent. Gaps would cause incorrect address calculations, leading + * to accessing wrong memory. + */ + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); #if CONFIG_LIBC_PICOLIBC _picolibc_reent_stub_start = ABSOLUTE(.); KEEP(*(.tdata.errno)) @@ -395,15 +411,18 @@ SECTIONS #endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY _picolibc_reent_stub_end = ABSOLUTE(.); #endif // CONFIG_LIBC_PICOLIBC - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) - _thread_local_end = ABSOLUTE(.); + *(.tdata .tdata.* .gnu.linkonce.td.*) + _thread_local_data_end = ABSOLUTE(.); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + _tls_section_alignment = ALIGNOF(.flash.tdata); ASSERT_PICOLIBC_REENT_STUB() - - _flash_rodata_align = ALIGNOF(.flash.rodata); + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") /** * This section contains all the rodata that is not used @@ -418,7 +437,7 @@ SECTIONS */ _rodata_reserved_end = ABSOLUTE(.); - mapping[rodata_noload] + SECTION_MAPPINGS(rodata_noload) } > default_rodata_seg .flash.text : @@ -431,7 +450,7 @@ SECTIONS _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); - mapping[flash_text] + SECTION_MAPPINGS(flash_text) *(.stub) *(.gnu.warning) @@ -472,7 +491,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _iram_data_start) - mapping[iram0_data] + SECTION_MAPPINGS(iram0_data) _iram_data_end = ABSOLUTE(.); } > iram0_0_seg @@ -481,7 +500,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _iram_bss_start) - mapping[iram0_bss] + SECTION_MAPPINGS(iram0_bss) _iram_bss_end = ABSOLUTE(.); ALIGNED_SYMBOL(4, _iram_end) @@ -494,7 +513,8 @@ SECTIONS ALIGNED_SYMBOL(8, _heap_low_start) } > dram0_0_seg -#include "elf_misc.ld.in" +#include "ld.debug.sections" +#include "ld.discard.sections" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32s2/memory.ld.in b/components/esp_system/ld/esp32s2/memory.ld.in index 82fa95625c..55214e7ca9 100644 --- a/components/esp_system/ld/esp32s2/memory.ld.in +++ b/components/esp_system/ld/esp32s2/memory.ld.in @@ -109,8 +109,6 @@ _heap_start = _heap_low_start; _heap_end = 0x40000000; -_data_seg_org = ORIGIN(rtc_data_seg); - /* The lines below define location alias for .rtc.data section based on Kconfig option. When the option is not defined then use slow memory segment else the data will be placed in fast memory segment */ diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index f73da10233..41fa979c92 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -28,7 +28,7 @@ SECTIONS HIDDEN(_rtc_code_start = .); - mapping[rtc_text] + SECTION_MAPPINGS(rtc_text) *rtc_wake_stub*.*(.literal .text .literal.* .text.*) @@ -63,7 +63,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_force_fast_start) - mapping[rtc_force_fast] + SECTION_MAPPINGS(rtc_force_fast) *(.rtc.force_fast .rtc.force_fast.*) @@ -82,7 +82,7 @@ SECTIONS { _rtc_data_start = ABSOLUTE(.); - mapping[rtc_data] + SECTION_MAPPINGS(rtc_data) *rtc_wake_stub*.*(.data .rodata .data.* .rodata.*) @@ -97,7 +97,7 @@ SECTIONS *rtc_wake_stub*.*(.bss .bss.*) *rtc_wake_stub*.*(COMMON) - mapping[rtc_bss] + SECTION_MAPPINGS(rtc_bss) _rtc_bss_end = ABSOLUTE(.); } > rtc_data_location @@ -114,6 +114,8 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_noinit_start) + SECTION_MAPPINGS(rtc_noinit) + *(.rtc_noinit .rtc_noinit.*) ALIGNED_SYMBOL(4, _rtc_noinit_end) @@ -211,7 +213,7 @@ SECTIONS /* Code marked as running out of IRAM */ _iram_text_start = ABSOLUTE(.); - mapping[iram0_text] + SECTION_MAPPINGS(iram0_text) /* Padding for possible CPU prefetch + alignment for PMS split lines */ . += _esp_memprot_prefetch_pad_size; @@ -239,7 +241,7 @@ SECTIONS *(.gnu.linkonce.s2.*) *(.jcr) - mapping[dram0_data] + SECTION_MAPPINGS(dram0_data) _data_end = ABSOLUTE(.); } > dram0_0_seg @@ -265,7 +267,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _ext_ram_bss_start) - mapping[extern_ram] + SECTION_MAPPINGS(extern_ram) ALIGNED_SYMBOL(4, _ext_ram_bss_end) } > extern_ram_seg @@ -280,6 +282,7 @@ SECTIONS { _ext_ram_noinit_start = ABSOLUTE(.); + SECTION_MAPPINGS(extram_noinit) *(.ext_ram_noinit*) ALIGNED_SYMBOL(4, _ext_ram_noinit_end) @@ -291,11 +294,7 @@ SECTIONS { ALIGNED_SYMBOL(8, _bss_start) - /** - * ldgen places all bss-related data to mapping[dram0_bss] - * (See components/esp_system/app.lf). - */ - mapping[dram0_bss] + SECTION_MAPPINGS(dram0_bss) ALIGNED_SYMBOL(8, _bss_end) } > dram0_0_seg @@ -329,7 +328,7 @@ SECTIONS { _flash_rodata_start = ABSOLUTE(.); - mapping[flash_rodata] + SECTION_MAPPINGS(flash_rodata) *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) @@ -347,16 +346,6 @@ SECTIONS __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); *(.xt_except_desc_end) -#if EH_FRAME_LINKING_ENABLED - ALIGNED_SYMBOL(4, __eh_frame) - KEEP(*(.eh_frame)) - /** - * As we are not linking with crtend.o, which includes the CIE terminator - * (see __FRAME_END__ in libgcc sources), it is manually provided here. - */ - LONG(0); -#endif // EH_FRAME_LINKING_ENABLED - /** * C++ constructor tables. * @@ -384,9 +373,37 @@ SECTIONS *(.lit4.*) *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(SECTION_AFTER_FLASH_RODATA)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.rodata, SECTION_AFTER_FLASH_RODATA) - /* TLS data. */ - ALIGNED_SYMBOL(4, _thread_local_start) +#if EH_FRAME_LINKING_ENABLED + .eh_frame : + { + ALIGNED_SYMBOL(4, __eh_frame) + + KEEP (*(.eh_frame)) + /** + * As we are not linking with crtend.o, which includes the CIE terminator + * (see __FRAME_END__ in libgcc sources), it is manually provided here. + */ + LONG(0); + + __eh_frame_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.tdata)); + } > default_rodata_seg +#endif // EH_FRAME_LINKING_ENABLED + + .flash.tdata : + { + /* Keep tdata and tbss sections contiguous (no gaps between them). + * The TLS runtime code calculates offsets assuming these sections are + * adjacent. Gaps would cause incorrect address calculations, leading + * to accessing wrong memory. + */ + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); #if CONFIG_LIBC_PICOLIBC _picolibc_reent_stub_start = ABSOLUTE(.); KEEP(*(.tdata.errno)) @@ -398,15 +415,18 @@ SECTIONS #endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY _picolibc_reent_stub_end = ABSOLUTE(.); #endif // CONFIG_LIBC_PICOLIBC - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) - _thread_local_end = ABSOLUTE(.); + *(.tdata .tdata.* .gnu.linkonce.td.*) + _thread_local_data_end = ABSOLUTE(.); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + _tls_section_alignment = ALIGNOF(.flash.tdata); ASSERT_PICOLIBC_REENT_STUB() - - _flash_rodata_align = ALIGNOF(.flash.rodata); + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") /** * This section contains all the rodata that is not used @@ -421,7 +441,8 @@ SECTIONS */ _rodata_reserved_end = ABSOLUTE(.); - mapping[rodata_noload] + SECTION_MAPPINGS(rodata_noload) + } > default_rodata_seg .flash.text : @@ -434,7 +455,7 @@ SECTIONS _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); - mapping[flash_text] + SECTION_MAPPINGS(flash_text) *(.stub) *(.gnu.warning) @@ -478,7 +499,8 @@ SECTIONS ALIGNED_SYMBOL(8, _heap_low_start) } > dram0_0_seg -#include "elf_misc.ld.in" +#include "ld.debug.sections" +#include "ld.discard.sections" } ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32s3/memory.ld.in b/components/esp_system/ld/esp32s3/memory.ld.in index ba229c649b..400efc22df 100644 --- a/components/esp_system/ld/esp32s3/memory.ld.in +++ b/components/esp_system/ld/esp32s3/memory.ld.in @@ -130,9 +130,6 @@ _heap_start = _heap_low_start; /* Heap ends at top of dram0_0_seg */ _heap_end = 0x40000000; -_data_seg_org = ORIGIN(rtc_data_seg); - - /* RTC fast memory shares the same range for both data and instructions */ REGION_ALIAS("rtc_data_seg", rtc_iram_seg ); diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index bf71a95412..7a12ddb7bb 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -24,7 +24,7 @@ SECTIONS *(.rtc.entry.literal .rtc.entry.text) - mapping[rtc_text] + SECTION_MAPPINGS(rtc_text) *rtc_wake_stub*.*(.literal .text .literal.* .text.*) *(.rtc_text_end_test) @@ -47,7 +47,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_force_fast_start) - mapping[rtc_force_fast] + SECTION_MAPPINGS(rtc_force_fast) *(.rtc.force_fast .rtc.force_fast.*) @@ -66,7 +66,7 @@ SECTIONS { _rtc_data_start = ABSOLUTE(.); - mapping[rtc_data] + SECTION_MAPPINGS(rtc_data) *rtc_wake_stub*.*(.data .rodata .data.* .rodata.*) @@ -81,7 +81,7 @@ SECTIONS *rtc_wake_stub*.*(.bss .bss.*) *rtc_wake_stub*.*(COMMON) - mapping[rtc_bss] + SECTION_MAPPINGS(rtc_bss) _rtc_bss_end = ABSOLUTE(.); } > rtc_data_location @@ -98,6 +98,8 @@ SECTIONS { ALIGNED_SYMBOL(4, _rtc_noinit_start) + SECTION_MAPPINGS(rtc_noinit) + *(.rtc_noinit .rtc_noinit.*) ALIGNED_SYMBOL(4, _rtc_noinit_end) @@ -195,8 +197,7 @@ SECTIONS /* Code marked as running out of IRAM */ _iram_text_start = ABSOLUTE(.); - mapping[iram0_text] - + SECTION_MAPPINGS(iram0_text) } > iram0_0_seg /** @@ -205,8 +206,7 @@ SECTIONS */ .dram0.dummy (NOLOAD): { - /* MAX() uses unsigned long arithmetic. Add offset to prevent underflow when _iram_end < _diram_i_start */ - . = ORIGIN(dram0_0_seg) + MAX(_iram_end - _diram_i_start + (_diram_i_start - ORIGIN(iram0_0_seg)), (_diram_i_start - ORIGIN(iram0_0_seg))) - (_diram_i_start - ORIGIN(iram0_0_seg)); + . = ORIGIN(dram0_0_seg) + ((_iram_end > _diram_i_start) ? (_iram_end - _diram_i_start) : 0); } > dram0_0_seg .dram0.data : @@ -220,7 +220,7 @@ SECTIONS *(.gnu.linkonce.s2.*) *(.jcr) - mapping[dram0_data] + SECTION_MAPPINGS(dram0_data) _data_end = ABSOLUTE(.); } > dram0_0_seg @@ -245,11 +245,7 @@ SECTIONS { ALIGNED_SYMBOL(8, _bss_start) - /** - * ldgen places all bss-related data to mapping[dram0_bss] - * (See components/esp_system/app.lf). - */ - mapping[dram0_bss] + SECTION_MAPPINGS(dram0_bss) ALIGNED_SYMBOL(8, _bss_end) } > dram0_0_seg @@ -267,7 +263,7 @@ SECTIONS _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); - mapping[flash_text] + SECTION_MAPPINGS(flash_text) *(.stub) *(.gnu.warning) @@ -341,7 +337,7 @@ SECTIONS { _flash_rodata_start = ABSOLUTE(.); - mapping[flash_rodata] + SECTION_MAPPINGS(flash_rodata) *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) @@ -359,16 +355,6 @@ SECTIONS __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); *(.xt_except_desc_end) -#if EH_FRAME_LINKING_ENABLED - ALIGNED_SYMBOL(4, __eh_frame) - KEEP(*(.eh_frame)) - /** - * As we are not linking with crtend.o, which includes the CIE terminator - * (see __FRAME_END__ in libgcc sources), it is manually provided here. - */ - LONG(0); -#endif // EH_FRAME_LINKING_ENABLED - /** * C++ constructor tables. * @@ -396,9 +382,37 @@ SECTIONS *(.lit4.*) *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(SECTION_AFTER_FLASH_RODATA)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.rodata, SECTION_AFTER_FLASH_RODATA) - /* TLS data. */ - ALIGNED_SYMBOL(4, _thread_local_start) +#if EH_FRAME_LINKING_ENABLED + .eh_frame : + { + ALIGNED_SYMBOL(4, __eh_frame) + + KEEP (*(.eh_frame)) + /** + * As we are not linking with crtend.o, which includes the CIE terminator + * (see __FRAME_END__ in libgcc sources), it is manually provided here. + */ + LONG(0); + + __eh_frame_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.tdata)); + } > default_rodata_seg +#endif // EH_FRAME_LINKING_ENABLED + + .flash.tdata : + { + /* Keep tdata and tbss sections contiguous (no gaps between them). + * The TLS runtime code calculates offsets assuming these sections are + * adjacent. Gaps would cause incorrect address calculations, leading + * to accessing wrong memory. + */ + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); #if CONFIG_LIBC_PICOLIBC _picolibc_reent_stub_start = ABSOLUTE(.); KEEP(*(.tdata.errno)) @@ -410,15 +424,18 @@ SECTIONS #endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY _picolibc_reent_stub_end = ABSOLUTE(.); #endif // CONFIG_LIBC_PICOLIBC - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) - _thread_local_end = ABSOLUTE(.); + *(.tdata .tdata.* .gnu.linkonce.td.*) + _thread_local_data_end = ABSOLUTE(.); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + _tls_section_alignment = ALIGNOF(.flash.tdata); ASSERT_PICOLIBC_REENT_STUB() - - _flash_rodata_align = ALIGNOF(.flash.rodata); + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") /** * This section contains all the rodata that is not used @@ -433,7 +450,7 @@ SECTIONS */ _rodata_reserved_end = ABSOLUTE(.); - mapping[rodata_noload] + SECTION_MAPPINGS(rodata_noload) } > default_rodata_seg /** @@ -453,7 +470,7 @@ SECTIONS { _ext_ram_bss_start = ABSOLUTE(.); - mapping[extern_ram] + SECTION_MAPPINGS(extern_ram) ALIGNED_SYMBOL(4, _ext_ram_bss_end) } > extern_ram_seg @@ -468,6 +485,7 @@ SECTIONS { _ext_ram_noinit_start = ABSOLUTE(.); + SECTION_MAPPINGS(extram_noinit) *(.ext_ram_noinit*) ALIGNED_SYMBOL(4, _ext_ram_noinit_end) @@ -491,7 +509,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _iram_data_start) - mapping[iram0_data] + SECTION_MAPPINGS(iram0_data) ALIGNED_SYMBOL(4, _iram_data_end) } > iram0_0_seg @@ -500,7 +518,7 @@ SECTIONS { ALIGNED_SYMBOL(4, _iram_bss_start) - mapping[iram0_bss] + SECTION_MAPPINGS(iram0_bss) _iram_bss_end = ABSOLUTE(.); ALIGNED_SYMBOL(4, _iram_end) @@ -513,7 +531,8 @@ SECTIONS ALIGNED_SYMBOL(8, _heap_low_start) } > dram0_0_seg -#include "elf_misc.ld.in" +#include "ld.debug.sections" +#include "ld.discard.sections" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/ld.common b/components/esp_system/ld/ld.common index 4c39566ae2..51e2d3f2eb 100644 --- a/components/esp_system/ld/ld.common +++ b/components/esp_system/ld/ld.common @@ -105,7 +105,12 @@ ASSERT((ADDR(NEXT_SECTION) == ADDR(PREV_SECTION) + SIZEOF(PREV_SECTION)), \ #endif #if EH_FRAME_LINKING_ENABLED +#if CONFIG_IDF_TARGET_ARCH_RISCV #define SECTION_AFTER_FLASH_RODATA .eh_frame_hdr +#endif +#if CONFIG_IDF_TARGET_ARCH_XTENSA +#define SECTION_AFTER_FLASH_RODATA .eh_frame +#endif #else #define SECTION_AFTER_FLASH_RODATA .flash.tdata #endif diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index a26a41c707..7e799a9d67 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -450,30 +450,36 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u LOW ADDRESS |---------------------------| Linker Symbols | Section | -------------- - | .flash.rodata | - 0x0|---------------------------| <- _flash_rodata_start - ^ | Other Data | - | |---------------------------| <- _thread_local_start - | | .tbss | ^ - V | | | - 0xNNN | int example; | | tls_area_size - | | | - | .tdata | V - |---------------------------| <- _thread_local_end + | .flash.tdata | + 0x0|---------------------------| <- _thread_local_data_start ^ + | .flash.tdata | | + | int var_1 = 1; | | + | | <- _thread_local_data_end | + | | <- _thread_local_bss_start | tls_area_size + | | | + | .flash.tbss (NOLOAD) | | + | int var_2; | | + |---------------------------| <- _thread_local_bss_end V | Other data | | ... | |---------------------------| HIGH ADDRESS */ // Calculate the TLS area's size (rounded up to multiple of 16 bytes). - extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align; - const uint32_t tls_area_size = ALIGNUP(16, (uint32_t)&_thread_local_end - (uint32_t)&_thread_local_start); + extern int _tls_section_alignment; + extern char _thread_local_data_start, _thread_local_data_end; + extern char _thread_local_bss_start, _thread_local_bss_end; + const uint32_t tls_data_size = (uint32_t)&_thread_local_data_end - (uint32_t)&_thread_local_data_start; + const uint32_t tls_bss_size = (uint32_t)&_thread_local_bss_end - (uint32_t)&_thread_local_bss_start; + const uint32_t tls_area_size = ALIGNUP(16, tls_data_size + tls_bss_size); // TODO: check that TLS area fits the stack // Allocate space for the TLS area on the stack. The area must be allocated at a 16-byte aligned address uxStackPointer = STACKPTR_ALIGN_DOWN(16, uxStackPointer - (UBaseType_t)tls_area_size); - // Initialize the TLS area with the initialization values of each TLS variable - memcpy((void *)uxStackPointer, &_thread_local_start, tls_area_size); + // Initialize the TLS data with the initialization values of each TLS variable + memcpy((void *)uxStackPointer, &_thread_local_data_start, tls_data_size); + // Initialize the TLS bss with zeroes + memset((void *)(uxStackPointer + tls_data_size), 0, tls_bss_size); /* Calculate the THREADPTR register's initialization value based on the link-time offset and the TLS area allocated on @@ -500,10 +506,10 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u - "offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment)" - TCB_SIZE is hardcoded to 8 */ - const uint32_t tls_section_align = (uint32_t)&_flash_rodata_align; // ALIGN value of .flash.rodata section + const uint32_t tls_section_align = (uint32_t)&_tls_section_alignment; // ALIGN value of .flash.tdata section #define TCB_SIZE 8 const uint32_t base = ALIGNUP(tls_section_align, TCB_SIZE); - *ret_threadptr_reg_init = (uint32_t)uxStackPointer - ((uint32_t)&_thread_local_start - (uint32_t)&_flash_rodata_start) - base; + *ret_threadptr_reg_init = (uint32_t)uxStackPointer - base; return uxStackPointer; } diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c index 2b5f5aadb0..4364d28f56 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c @@ -8,7 +8,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2023-2026 Espressif Systems (Shanghai) CO LTD * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -220,30 +220,36 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u LOW ADDRESS |---------------------------| Linker Symbols | Section | -------------- - | .flash.rodata | - 0x0|---------------------------| <- _flash_rodata_start - ^ | Other Data | - | |---------------------------| <- _thread_local_start - | | .tbss | ^ - V | | | - 0xNNN | int example; | | tls_area_size - | | | - | .tdata | V - |---------------------------| <- _thread_local_end + | .flash.tdata | + 0x0|---------------------------| <- _thread_local_data_start ^ + | .flash.tdata | | + | int var_1 = 1; | | + | | <- _thread_local_data_end | + | | <- _thread_local_bss_start | tls_area_size + | | | + | .flash.tbss (NOLOAD) | | + | int var_2; | | + |---------------------------| <- _thread_local_bss_end V | Other data | | ... | |---------------------------| HIGH ADDRESS */ // Calculate the TLS area's size (rounded up to multiple of 16 bytes). - extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align; - const uint32_t tls_area_size = ALIGNUP(16, (uint32_t)&_thread_local_end - (uint32_t)&_thread_local_start); + extern int _tls_section_alignment; + extern char _thread_local_data_start, _thread_local_data_end; + extern char _thread_local_bss_start, _thread_local_bss_end; + const uint32_t tls_data_size = (uint32_t)&_thread_local_data_end - (uint32_t)&_thread_local_data_start; + const uint32_t tls_bss_size = (uint32_t)&_thread_local_bss_end - (uint32_t)&_thread_local_bss_start; + const uint32_t tls_area_size = ALIGNUP(16, tls_data_size + tls_bss_size); // TODO: check that TLS area fits the stack // Allocate space for the TLS area on the stack. The area must be allocated at a 16-byte aligned address uxStackPointer = STACKPTR_ALIGN_DOWN(16, uxStackPointer - (UBaseType_t)tls_area_size); - // Initialize the TLS area with the initialization values of each TLS variable - memcpy((void *)uxStackPointer, &_thread_local_start, tls_area_size); + // Initialize the TLS data with the initialization values of each TLS variable + memcpy((void *)uxStackPointer, &_thread_local_data_start, tls_data_size); + // Initialize the TLS bss with zeroes + memset((void *)(uxStackPointer + tls_data_size), 0, tls_bss_size); /* Calculate the THREADPTR register's initialization value based on the link-time offset and the TLS area allocated on @@ -270,10 +276,10 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u - "offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment)" - TCB_SIZE is hardcoded to 8 */ - const uint32_t tls_section_align = (uint32_t)&_flash_rodata_align; // ALIGN value of .flash.rodata section + const uint32_t tls_section_align = (uint32_t)&_tls_section_alignment; // ALIGN value of .flash.tdata section #define TCB_SIZE 8 const uint32_t base = ALIGNUP(tls_section_align, TCB_SIZE); - *ret_threadptr_reg_init = (uint32_t)uxStackPointer - ((uint32_t)&_thread_local_start - (uint32_t)&_flash_rodata_start) - base; + *ret_threadptr_reg_init = (uint32_t)uxStackPointer - base; return uxStackPointer; }