diff --git a/components/esp_system/ld/esp32h4/memory.ld.in b/components/esp_system/ld/esp32h4/memory.ld.in index 0b892b05e5..ac79824bb4 100644 --- a/components/esp_system/ld/esp32h4/memory.ld.in +++ b/components/esp_system/ld/esp32h4/memory.ld.in @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,23 +17,11 @@ #include "sdkconfig.h" #include "ld.common" -/** - * physical memory is mapped twice to the virtual address (IRAM and DRAM). - * `I_D_SRAM_OFFSET` is the offset between the two locations of the same physical memory - */ - /* TODO: IDF-12517 */ -#define SRAM_IRAM_START 0x40810000 -#define SRAM_DRAM_START 0x40810000 +#define SRAM_SEG_START 0x40810000 +#define SRAM_SEG_END 0x4084f350 /* 2nd stage bootloader iram_loader_seg start address */ +#define SRAM_SEG_SIZE SRAM_SEG_END - SRAM_SEG_START -#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START) -#define SRAM_DRAM_END 0x4084f350 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */ - -/* TODO: IDF-12565 */ -#define SRAM_IRAM_ORG (SRAM_IRAM_START) -#define SRAM_DRAM_ORG (SRAM_DRAM_START) - -#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* @@ -42,8 +30,6 @@ #define IDRAM0_2_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 8) #endif -#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE - MEMORY { /** @@ -52,9 +38,6 @@ MEMORY * are connected to the data port of the CPU and eg allow byte-wise access. */ - /* IRAM for PRO CPU. */ - iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE - #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped instruction data */ irom_seg (RX) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20 @@ -72,7 +55,7 @@ MEMORY * Shared data RAM, excluding memory reserved for ROM bss/data/stack. * Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available. */ - dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN + sram_seg (RWX) : org = SRAM_SEG_START, len = SRAM_SEG_SIZE #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped constant data */ @@ -83,19 +66,19 @@ MEMORY } -/* Heap ends at top of dram0_0_seg */ +/* Heap ends at top of sram_seg */ _heap_end = 0x40000000; #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS REGION_ALIAS("default_code_seg", irom_seg); #else - REGION_ALIAS("default_code_seg", iram0_0_seg); + REGION_ALIAS("default_code_seg", sram_seg); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS REGION_ALIAS("default_rodata_seg", drom_seg); #else - REGION_ALIAS("default_rodata_seg", dram0_0_seg); + REGION_ALIAS("default_rodata_seg", sram_seg); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /** diff --git a/components/esp_system/ld/esp32h4/sections.ld.in b/components/esp_system/ld/esp32h4/sections.ld.in index 1795f4d867..9e5761b2c1 100644 --- a/components/esp_system/ld/esp32h4/sections.ld.in +++ b/components/esp_system/ld/esp32h4/sections.ld.in @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,61 +18,44 @@ SECTIONS { _iram_start = ABSOLUTE(.); /* Vectors go to start of IRAM */ - ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned"); + ASSERT(ABSOLUTE(.) % 0x40 == 0, "vector address must be 64 byte aligned"); KEEP(*(.exception_vectors_table.text)); KEEP(*(.exception_vectors.text)); - . = ALIGN(4); - - _invalid_pc_placeholder = ABSOLUTE(.); /* Code marked as running out of IRAM */ _iram_text_start = ABSOLUTE(.); mapping[iram0_text] - } > iram0_0_seg + } > sram_seg /* Marks the end of IRAM code segment */ .iram0.text_end (NOLOAD) : { - /* ESP32-H4 memprot requires 16B padding for possible CPU prefetch and 512B alignment for PMS split lines */ - . += _esp_memprot_prefetch_pad_size; - . = ALIGN(_esp_memprot_align_size); - /* iram_end_test section exists for use by memprot unit tests only */ - *(.iram_end_test) - _iram_text_end = ABSOLUTE(.); - } > iram0_0_seg + /* Align the end of code region as per PMP region granularity */ + . = ALIGN(_esp_pmp_align_size); + + ALIGNED_SYMBOL(4, _iram_text_end) + } > sram_seg .iram0.data : { - . = ALIGN(16); - _iram_data_start = ABSOLUTE(.); + ALIGNED_SYMBOL(16, _iram_data_start) mapping[iram0_data] _iram_data_end = ABSOLUTE(.); - } > iram0_0_seg + } > sram_seg .iram0.bss (NOLOAD) : { - . = ALIGN(16); - _iram_bss_start = ABSOLUTE(.); + ALIGNED_SYMBOL(16, _iram_bss_start) mapping[iram0_bss] _iram_bss_end = ABSOLUTE(.); - . = ALIGN(16); - _iram_end = ABSOLUTE(.); - } > iram0_0_seg - - /** - * This section is required to skip .iram0.text area because iram0_0_seg and - * dram0_0_seg reflect the same address space on different buses. - */ - .dram0.dummy (NOLOAD): - { - . = ORIGIN(dram0_0_seg) + _iram_end - _iram_start; - } > dram0_0_seg + ALIGNED_SYMBOL(16, _iram_end) + } > sram_seg .dram0.data : { @@ -89,8 +72,7 @@ SECTIONS mapping[dram0_data] _data_end = ABSOLUTE(.); - . = ALIGN(4); - } > dram0_0_seg + } > sram_seg /** * This section holds data that should not be initialized at power up. @@ -100,62 +82,60 @@ SECTIONS */ .noinit (NOLOAD): { - . = ALIGN(4); - _noinit_start = ABSOLUTE(.); + ALIGNED_SYMBOL(4, _noinit_start) + *(.noinit .noinit.*) - . = ALIGN(4) ; - _noinit_end = ABSOLUTE(.); - } > dram0_0_seg + + ALIGNED_SYMBOL(4, _noinit_end) + } > sram_seg /* Shared RAM */ .dram0.bss (NOLOAD) : { - . = ALIGN (8); - _bss_start = ABSOLUTE(.); + ALIGNED_SYMBOL(8, _bss_start) + /** + * ldgen places all bss-related data to mapping[dram0_bss] + * (See components/esp_system/app.lf). + */ mapping[dram0_bss] - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - *(.dynbss) - *(.share.mem) - *(.gnu.linkonce.b.*) + ALIGNED_SYMBOL(8, _bss_end) + } > sram_seg - . = ALIGN (8); - _bss_end = ABSOLUTE(.); - } > dram0_0_seg - - ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.") + ASSERT(((_bss_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), "DRAM segment data does not fit.") .flash.text : { _stext = .; - _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ + /** + * Mark the start of flash.text. + * This can be used by the MMU driver to maintain the virtual address. + */ + _instruction_reserved_start = ABSOLUTE(.); _text_start = ABSOLUTE(.); mapping[flash_text] - *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.stub) + *(.gnu.linkonce.t.*) + *(.gnu.warning) *(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */ - *(.fini.literal) - *(.fini) - *(.gnu.version) - /** CPU will try to prefetch up to 16 bytes of - * of instructions. This means that any configuration (e.g. MMU, PMS) must allow - * safe access to up to 16 bytes after the last real instruction, add - * dummy bytes to ensure this - */ + /** + * CPU will try to prefetch up to 16 bytes of of instructions. + * This means that any configuration (e.g. MMU, PMS) must allow + * safe access to up to 16 bytes after the last real instruction, add + * dummy bytes to ensure this + */ . += _esp_flash_mmap_prefetch_pad_size; _text_end = ABSOLUTE(.); - _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ + /** + * Mark the flash.text end. + * This can be used for MMU driver to maintain virtual address. + */ + _instruction_reserved_end = ABSOLUTE(.); _etext = .; /** @@ -167,34 +147,43 @@ SECTIONS } > default_code_seg /** - * This dummy section represents the .flash.text section but in default_rodata_seg. + * Dummy section represents the .flash.text section but in default_rodata_seg. * Thus, it must have its alignment and (at least) its size. */ .flash_rodata_dummy (NOLOAD): { _flash_rodata_dummy_start = .; - /* Start at the same alignment constraint than .flash.text */ - . = ALIGN(ALIGNOF(.flash.text)); - /* Create an empty gap as big as .flash.text section */ - . = . + SIZEOF(.flash.text); - /* Prepare the alignment of the section above. Few bytes (0x20) must be - * added for the mapping header. */ + + . = ALIGN(ALIGNOF(.flash.text)) + SIZEOF(.flash.text); + + /* Add alignment of MMU page size + 0x20 bytes for the mapping header. */ . = ALIGN(_esp_mmu_page_size) + 0x20; } > default_rodata_seg .flash.appdesc : ALIGN(0x10) { - _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ + /** + * Mark flash.rodata start. + * This can be used for mmu driver to maintain virtual address + */ + _rodata_reserved_start = ABSOLUTE(.); _rodata_start = ABSOLUTE(.); - *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ - *(.rodata_custom_desc .rodata_custom_desc.*) /* Should be the second. Custom app version info. DO NOT PUT ANYTHING BEFORE IT! */ + /* !DO NOT PUT ANYTHING BEFORE THIS! */ - /* Create an empty gap within this section. Thanks to this, the end of this + /* Should be the first. App version info. */ + *(.rodata_desc .rodata_desc.*) + /* Should be the second. Custom app version info. */ + *(.rodata_custom_desc .rodata_custom_desc.*) + + /** + * Create an empty gap within this section. Thanks to this, the end of this * section will match .flash.rodata's begin address. Thus, both sections - * will be merged when creating the final bin image. */ + * will be merged when creating the final bin image. + */ . = ALIGN(ALIGNOF(.flash.rodata)); - } >default_rodata_seg + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata) .flash.rodata : ALIGN(0x10) { @@ -205,86 +194,75 @@ SECTIONS *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) - __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); - *(.xt_except_table) *(.gcc_except_table .gcc_except_table.*) *(.gnu.linkonce.e.*) - *(.gnu.version_r) - . = (. + 7) & ~ 3; - /* - * C++ constructor and destructor tables - * Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt. + /** + * C++ constructor tables. * - * RISC-V gcc is configured with --enable-initfini-array so it emits an .init_array section instead. - * But the init_priority sections will be sorted for iteration in ascending order during startup. - * The rest of the init_array sections is sorted for iteration in descending order during startup, however. - * Hence a different section is generated for the init_priority functions which is iterated in - * ascending order during startup. The corresponding code can be found in startup.c. + * Excluding crtbegin.o/crtend.o since IDF doesn't use the toolchain crt. + * + * RISC-V gcc is configured with --enable-initfini-array so it emits + * .init_array section instead. But the init_priority sections will be + * sorted for iteration in ascending order during startup. + * The rest of the init_array sections is sorted for iteration in descending + * order during startup, however. Hence a different section is generated for + * the init_priority functions which is iterated in ascending order during + * startup. The corresponding code can be found in startup.c. */ - __init_priority_array_start = ABSOLUTE(.); + ALIGNED_SYMBOL(4, __init_priority_array_start) KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*)) __init_priority_array_end = ABSOLUTE(.); - __init_array_start = ABSOLUTE(.); + + ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) __init_array_end = ABSOLUTE(.); - KEEP (*crtbegin.*(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - /* C++ exception handlers table: */ - __XT_EXCEPTION_DESCS_ = ABSOLUTE(.); - *(.xt_except_desc) - *(.gnu.linkonce.h.*) - __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); - *(.xt_except_desc_end) - *(.dynamic) - *(.gnu.version_d) + /* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */ - soc_reserved_memory_region_start = ABSOLUTE(.); + ALIGNED_SYMBOL(4, soc_reserved_memory_region_start) KEEP (*(.reserved_memory_address)) soc_reserved_memory_region_end = ABSOLUTE(.); + /* System init functions registered via ESP_SYSTEM_INIT_FN */ - _esp_system_init_fn_array_start = ABSOLUTE(.); + ALIGNED_SYMBOL(4, _esp_system_init_fn_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(.esp_system_init_fn.*))) _esp_system_init_fn_array_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); - /* Literals are also RO data. */ - _lit4_start = ABSOLUTE(.); - *(*.lit4) - *(.lit4.*) - *(.gnu.linkonce.lit4.*) - _lit4_end = ABSOLUTE(.); - . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) - _thread_local_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(SECTION_AFTER_FLASH_RODATA)); + } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.rodata, SECTION_AFTER_FLASH_RODATA) + +#if EH_FRAME_LINKING_ENABLED + .eh_frame_hdr : + { + ALIGNED_SYMBOL(4, __eh_frame_hdr) + + KEEP (*(.eh_frame_hdr)) + + __eh_frame_hdr_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) - /* Keep this section shall be at least aligned on 4 */ - .eh_frame : ALIGN(8) + .eh_frame : { - __eh_frame = ABSOLUTE(.); + 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(.); - /* Guarantee that this section and the next one will be merged by making - * them adjacent. */ - . = ALIGN(ALIGNOF(.eh_frame_hdr)); - } > default_rodata_seg - /* To avoid any exception in C++ exception frame unwinding code, this section - * shall be aligned on 8. */ - .eh_frame_hdr : ALIGN(8) - { - __eh_frame_hdr = ABSOLUTE(.); - KEEP (*(.eh_frame_hdr)) - __eh_frame_hdr_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) +#endif // EH_FRAME_LINKING_ENABLED - /* TODO [ESP32H4] */ .flash.tdata : { _thread_local_data_start = ABSOLUTE(.); @@ -306,32 +284,33 @@ SECTIONS _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg - /* - This section is a place where we dump all the rodata which aren't used at runtime, - so as to avoid binary size increase - */ + /** + * This section contains all the rodata that is not used + * at runtime, helping to avoid an increase in binary size. + */ .flash.rodata_noload (NOLOAD) : { - /* - This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address - We don't need to include the noload rodata in this section - */ - _rodata_reserved_end = ABSOLUTE(.); - . = ALIGN (4); + /** + * This symbol marks the end of flash.rodata. It can be utilized by the MMU + * driver to maintain the virtual address. + * NOLOAD rodata may not be included in this section. + */ + _rodata_reserved_end = ADDR(.flash.tbss); + mapping[rodata_noload] } > default_rodata_seg - /* Marks the end of data, bss and possibly rodata */ + /* Marks the end of data, bss and possibly rodata */ .dram0.heap_start (NOLOAD) : { - . = ALIGN (16); - _heap_start = ABSOLUTE(.); - } > dram0_0_seg + ALIGNED_SYMBOL(16, _heap_start) + } > sram_seg + #include "elf_misc.ld.in" } -ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), +ASSERT(((_iram_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), "IRAM0 segment data does not fit.") -ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), +ASSERT(((_heap_start - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), "DRAM segment data does not fit.")