From 21fa93e55a3da6698e8361be17727ce442b14c7f Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 10 Dec 2025 16:35:43 +0700 Subject: [PATCH 01/18] feat(tools): update toolchain version to esp-14.2.0_20260121 --- tools/tools.json | 112 +++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index 1b58a6a4179..48e0f0c88f4 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -182,51 +182,51 @@ "versions": [ { "linux-amd64": { - "sha256": "b0065b3b28d2b5d3bf4868f2fda6bc95d6081025583d1c17b286884bead0305d", - "size": 176948400, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-x86_64-linux-gnu.tar.xz" + "sha256": "da31f36d79d4e99f24e55a90a71e65d5694714f16199960bf7885724b706a48c", + "size": 176559292, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "571f1d3d4aa46f75d86f4c0f5c6c492fac6849de8345dae919875fa087c59591", - "size": 172565944, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-aarch64-linux-gnu.tar.xz" + "sha256": "80ae10ce3d6c02e8c06213f03cac343c4ef6f0fbd89f28530b918f7a1006f1eb", + "size": 171504672, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-aarch64-linux-gnu.tar.xz" }, "linux-armel": { - "sha256": "f8f3acabdea942ad42e8ad8748aaae993dfb6ba6c552d7e701ca42d90d857317", - "size": 170518776, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-arm-linux-gnueabi.tar.xz" + "sha256": "10d8279f286d205a508b97b5440e7ba402b57e48158c02fa18a4bfe1f183fe42", + "size": 172620104, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-arm-linux-gnueabi.tar.xz" }, "linux-armhf": { - "sha256": "c028f6902d652092b73655eba3780a120e901a24cff184d0be104a3e44c3d54a", - "size": 171649224, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-arm-linux-gnueabihf.tar.xz" + "sha256": "f1d6296a1e263aa8de9bbcb6f80ebc609ed3385b2905441786ceb05e96de0606", + "size": 169985628, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-arm-linux-gnueabihf.tar.xz" }, "linux-i686": { - "sha256": "d86fb12480129b722c2cb7515fbcb6a066083b50a38c33c193f2f17eede70575", - "size": 180444520, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-i586-linux-gnu.tar.xz" + "sha256": "c60f2991e3e59c1599fa4f03e9ca172958c23761e403c1015349bdd874cc73dd", + "size": 188758352, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-i586-linux-gnu.tar.xz" }, "macos": { - "sha256": "9a0f6f4d83ff39af41f1d2ebbf4683668c95d4a47a3bf5b1fa74eef80f3af1bb", - "size": 183731136, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-x86_64-apple-darwin.tar.xz" + "sha256": "02e5e3421222c9a708b21eca7826acb137668b188cb46fbde46339b26d4b2eeb", + "size": 177355744, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "cffc8213e8e5fea03d12e027868d743ff4d23263e6d45a98b03d18adec6454de", - "size": 168886320, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-aarch64-apple-darwin.tar.xz" + "sha256": "a450db49cea5f191a96345c5b7f0e1a9671a9cf132fecfd9fb1faf6c2a30637e", + "size": 170666656, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-aarch64-apple-darwin.tar.xz" }, - "name": "esp-14.2.0_20251107", + "name": "esp-14.2.0_20260121", "status": "recommended", "win32": { - "sha256": "70778f0e7dad518f9e6547911bedd6e23c48775313c7ed92f1cb04a86cea2351", - "size": 391481671, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-i686-w64-mingw32.zip" + "sha256": "d57eeb3783bce663cca312323ac9b305a22dfab479c642320c62aeefcc536ac0", + "size": 411000830, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-i686-w64-mingw32.zip" }, "win64": { - "sha256": "b0de5062da2f05d1773d1537421134e2a7517bd74a06c3b5763b07f94e38bece", - "size": 396056136, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/xtensa-esp-elf-14.2.0_20251107-x86_64-w64-mingw32.zip" + "sha256": "82cbe0353c2e7c96acc8755c854aaa2d93d346c6a378fc692e60b3912c560108", + "size": 413859845, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/xtensa-esp-elf-14.2.0_20260121-x86_64-w64-mingw32.zip" } } ] @@ -395,51 +395,51 @@ "versions": [ { "linux-amd64": { - "sha256": "1d3a1b6a064686d9b77c4db7731f82e26c072e312e27969c45fe96410ecb2671", - "size": 306966476, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-x86_64-linux-gnu.tar.xz" + "sha256": "b3fce4b04dd15a9f0ed1c209b5a2f389c04eff92ed85e4cc0ebc275b7d95e95a", + "size": 292412032, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "072a553453691fbd98fe82b6efa9a2fa6beb7d2c90aed4463353bc33378e83bf", - "size": 299897524, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-aarch64-linux-gnu.tar.xz" + "sha256": "61bea5c55a6a5a592b97a822e7ee5f75618a00d24441ce15e3a06f57da7188c9", + "size": 284818756, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-aarch64-linux-gnu.tar.xz" }, "linux-armel": { - "sha256": "2da03aa3497dbff897cc8bb879b2138ba141e8071edec1a2e43b334f98de6424", - "size": 297707224, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-arm-linux-gnueabi.tar.xz" + "sha256": "42975e91924d9dd48a093438d672f26ace9e5d9088b66da1a60586c3cbadfdd5", + "size": 283603716, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-arm-linux-gnueabi.tar.xz" }, "linux-armhf": { - "sha256": "6e4bee2ec2c8e922a890b59731746853ea8f14e118fcd6ae5fa58fea5c1aa2eb", - "size": 297953904, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-arm-linux-gnueabihf.tar.xz" + "sha256": "61aab57ae4680acbfdef51d74e052b88dcccc2b664cb517a12eab190b7df547b", + "size": 284371840, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-arm-linux-gnueabihf.tar.xz" }, "linux-i686": { - "sha256": "402ed7d177e744916df8afc74c5e5a9cfd40557df07a6a7fc52b00917b15f97b", - "size": 309687076, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-i586-linux-gnu.tar.xz" + "sha256": "cf7e310079cde38b870a502775d97222348b02be577b2bcaced01e6d51cb7512", + "size": 296283596, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-i586-linux-gnu.tar.xz" }, "macos": { - "sha256": "d413836fa000f095d041a35950a45f82e2ff669995c8d6a09fa4d05e5c4ed258", - "size": 309020528, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-x86_64-apple-darwin.tar.xz" + "sha256": "a690ca49198a2181ea7212563ba356b1460f2f9f1b190bef401907bf90646b78", + "size": 296934608, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "cedfcdaf8f165bd3e11ca4ee46b71d5b561fab93407eb8203812f9c14b1c7714", - "size": 288327120, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-aarch64-apple-darwin.tar.xz" + "sha256": "caa7103e014c61939eea4656cd4effdc34930da0b76cd59ad1adb7bfaeef923c", + "size": 289213048, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-aarch64-apple-darwin.tar.xz" }, - "name": "esp-14.2.0_20251107", + "name": "esp-14.2.0_20260121", "status": "recommended", "win32": { - "sha256": "7670128df99adbdcbc99ebbdccda19347daf2fd191aab1eb22c24ae1c4d77226", - "size": 690936765, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-i686-w64-mingw32.zip" + "sha256": "6f2c8f95866bdd72a96d0823f902b3e7466220f57470b5070ed5d6e99cddfa99", + "size": 698364886, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-i686-w64-mingw32.zip" }, "win64": { - "sha256": "373abecd1cdfd480b09b8659e319e636064f99fec46f635a05c5413e5f009c05", - "size": 697522467, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20251107/riscv32-esp-elf-14.2.0_20251107-x86_64-w64-mingw32.zip" + "sha256": "c2734714e59f684b74d1cb278f75b4ae9ec546aa1e55d73786ef039410e4a8f7", + "size": 705866147, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-14.2.0_20260121/riscv32-esp-elf-14.2.0_20260121-x86_64-w64-mingw32.zip" } } ] From 1c08b38b27302037d4672829273a6556f2e70653 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Mon, 10 Nov 2025 18:25:39 +0700 Subject: [PATCH 02/18] feat(build): propagate compiler flags from files to toolchain.cmake This change improves build consistency across external projects integrated through CMake by ensuring that compiler flags defined in configuration files are passed correctly to the toolchain. It covers the majority of use cases, as external projects are typically also CMake-based. For projects that use a custom build system, users will still need to specify the required flags manually. --- components/esp_hw_support/CMakeLists.txt | 9 +- components/esp_psram/CMakeLists.txt | 3 +- components/esp_psram/project_include.cmake | 45 ++++-- components/newlib/CMakeLists.txt | 2 - components/newlib/project_include.cmake | 24 +++- components/riscv/project_include.cmake | 5 - components/soc/project_include.cmake | 89 ++++++++++++ tools/cmake/project.cmake | 7 - tools/cmake/targets.cmake | 43 +++--- tools/cmake/toolchain-esp32.cmake | 23 +-- tools/cmake/toolchain-esp32c2.cmake | 17 +-- tools/cmake/toolchain-esp32c3.cmake | 19 +-- tools/cmake/toolchain-esp32c5.cmake | 17 +-- tools/cmake/toolchain-esp32c6.cmake | 17 +-- tools/cmake/toolchain-esp32c61.cmake | 17 +-- tools/cmake/toolchain-esp32h2.cmake | 17 +-- tools/cmake/toolchain-esp32h21.cmake | 18 +-- tools/cmake/toolchain-esp32h4.cmake | 20 +-- tools/cmake/toolchain-esp32p4.cmake | 23 +-- tools/cmake/toolchain-esp32s2.cmake | 23 +-- tools/cmake/toolchain-esp32s3.cmake | 23 +-- tools/cmake/toolchain.cmake | 85 +++++++++++ tools/cmake/toolchain_flags.cmake | 157 +++++++++++++++++++++ 23 files changed, 421 insertions(+), 282 deletions(-) delete mode 100644 components/riscv/project_include.cmake create mode 100644 components/soc/project_include.cmake create mode 100644 tools/cmake/toolchain.cmake create mode 100644 tools/cmake/toolchain_flags.cmake diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 6fe325a1c1f..25b804040b0 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -198,13 +198,8 @@ if(CONFIG_IDF_TARGET_ESP32H4) ) endif() - -if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) - if(CMAKE_C_COMPILER_ID MATCHES "GNU") - idf_build_set_property(COMPILE_OPTIONS "-march=rv32imafc_zicsr_zifencei_xesppie" APPEND) - endif() -elseif(CONFIG_IDF_TARGET_ESP32P4) - if(CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO: LLVM-478 +if(NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3 AND CONFIG_IDF_TARGET_ESP32P4) + if(CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO: LLVM-478 IDF-14338 message(FATAL_ERROR "ESP32-P4 rev. 3.0 or higher is not supported in Clang-based toolchain") endif() endif() diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt index 53e5f00d237..119138d392b 100644 --- a/components/esp_psram/CMakeLists.txt +++ b/components/esp_psram/CMakeLists.txt @@ -50,7 +50,8 @@ if(CONFIG_SPIRAM) endif() -if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) +# TODO IDF-14338 +if(CONFIG_IDF_TOOLCHAIN_CLANG AND CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) # Note: Adding as a PUBLIC compile option here causes this option to propagate to all # components that depend on esp_psram. # diff --git a/components/esp_psram/project_include.cmake b/components/esp_psram/project_include.cmake index 4e77c0389e5..aa9ff60758f 100644 --- a/components/esp_psram/project_include.cmake +++ b/components/esp_psram/project_include.cmake @@ -1,17 +1,34 @@ -if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) - # We do this here as well as in CMakeLists.txt, because targets that - # are not part of the ESP-IDF build system (for cases where a generic - # non-IDF CMakeLists.txt file is imported into a component) don't depend - # on the esp32 component so don't get the extra flag. This handles that case. - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue" APPEND) - # note that we don't need to set link options as the library linked is independent of this - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=dupldst" APPEND) +if(CONFIG_IDF_TOOLCHAIN_GCC) + # Remove all "-mfix-esp32-psram-cache*" from toolchain flags + # that may have appeared during configuration changes. + idf_toolchain_remove_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache") + if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue") + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=dupldst") + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=memw") + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=nops") + endif() endif() - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=memw" APPEND) - endif() - if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) - idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=nops" APPEND) +else() + if(CONFIG_IDF_TARGET_ESP32 AND CONFIG_SPIRAM_CACHE_WORKAROUND AND NOT BOOTLOADER_BUILD) + # We do this here as well as in CMakeLists.txt, because targets that + # are not part of the ESP-IDF build system (for cases where a generic + # non-IDF CMakeLists.txt file is imported into a component) don't depend + # on the esp32 component so don't get the extra flag. This handles that case. + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-issue" APPEND) + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST) + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=dupldst" APPEND) + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW) + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=memw" APPEND) + endif() + if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS) + idf_build_set_property(COMPILE_OPTIONS "-mfix-esp32-psram-cache-strategy=nops" APPEND) + endif() endif() endif() diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 1f88a944230..d7c0a0bf882 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -117,8 +117,6 @@ if(CONFIG_LIBC_NEWLIB_NANO_FORMAT) ) get_filename_component(libc_dir ${libc_dir} DIRECTORY) target_link_directories(${COMPONENT_LIB} INTERFACE "${libc_dir}/nano") - else() - target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs") endif() endif() diff --git a/components/newlib/project_include.cmake b/components/newlib/project_include.cmake index 62922378469..e3651702835 100644 --- a/components/newlib/project_include.cmake +++ b/components/newlib/project_include.cmake @@ -1,3 +1,23 @@ -if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) - idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND) +if(CONFIG_IDF_TOOLCHAIN_GCC) + if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mdisable-hardware-atomics") + else() + idf_toolchain_remove_flags(COMPILE_OPTIONS "-mdisable-hardware-atomics") + endif() + + if(CONFIG_LIBC_PICOLIBC) + idf_toolchain_add_flags(COMPILE_OPTIONS "-specs=picolibc.specs") + else() + idf_toolchain_remove_flags(COMPILE_OPTIONS "-specs=picolibc.specs") + endif() + + if(CONFIG_LIBC_NEWLIB_NANO_FORMAT) + idf_toolchain_add_flags(LINK_OPTIONS "--specs=nano.specs") + else() + idf_toolchain_remove_flags(LINK_OPTIONS "--specs=nano.specs") + endif() +else() # TODO IDF-14338 + if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) + idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND) + endif() endif() diff --git a/components/riscv/project_include.cmake b/components/riscv/project_include.cmake deleted file mode 100644 index b50a98454df..00000000000 --- a/components/riscv/project_include.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# avoid esp-clang "unused-command-line-argument" warning -if(NOT (CMAKE_C_COMPILER_ID MATCHES "Clang") ) - set(compile_options "-nostartfiles") - idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND) -endif() diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake new file mode 100644 index 00000000000..bbc288c2817 --- /dev/null +++ b/components/soc/project_include.cmake @@ -0,0 +1,89 @@ +if(CONFIG_IDF_TOOLCHAIN_GCC) + # Common flags + idf_toolchain_add_flags(LINK_OPTIONS "-nostartfiles") + + # Target-specific flags + if(CONFIG_IDF_TARGET_ESP32) + idf_toolchain_add_flags(COMPILE_OPTIONS "-Wno-frame-address") + elseif(CONFIG_IDF_TARGET_ESP32C2 OR + CONFIG_IDF_TARGET_ESP32C3) + set(_march "rv32imc_zicsr_zifencei") + elseif(CONFIG_IDF_TARGET_ESP32C5 OR + CONFIG_IDF_TARGET_ESP32C6 OR + CONFIG_IDF_TARGET_ESP32C61 OR + CONFIG_IDF_TARGET_ESP32H2 OR + CONFIG_IDF_TARGET_ESP32H21) + set(_march "rv32imac_zicsr_zifencei_zaamo_zalrsc") + elseif(CONFIG_IDF_TARGET_ESP32H4) + set(_march "rv32imafcb_zicsr_zifencei_zaamo_zalrsc") + elseif(CONFIG_IDF_TARGET_ESP32P4) + set(_march "rv32imafc_zicsr_zifencei_zaamo_zalrsc") + elseif(NOT(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3)) + message(FATAL_ERROR "Unknown Espressif target: ${CONFIG_IDF_TARGET}") + endif() + + # Architecture-specific flags + if(CONFIG_IDF_TARGET_ARCH_XTENSA) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mlongcalls" + "-fno-builtin-memcpy" + "-fno-builtin-memset" + "-fno-builtin-bzero") + elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + if(NOT DEFINED _march) + message(FATAL_ERROR "-march option is not defined for target ${CONFIG_IDF_TARGET}!") + endif() + + # Clean compile options that were added by previous configurations and may be outdated + idf_toolchain_remove_flags(COMPILE_OPTIONS "-march=") + + if(CONFIG_SOC_CPU_HAS_HWLOOP) + set(_march "${_march}_xesploop") + endif() + + if(CONFIG_SOC_CPU_HAS_PIE) + set(_march "${_march}_xespv") + if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + set(_march "${_march}2p1") + endif() + endif() + + if(CONFIG_SOC_CPU_HAS_DSP) + set(_march "${_march}_xespdsp") + endif() + + # Set ABI and ARCH options + if(CONFIG_SOC_CPU_HAS_FPU) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mabi=ilp32f") + endif() + idf_toolchain_add_flags(COMPILE_OPTIONS "-march=${_march}") + + if(NOT CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mtune=esp-base") + endif() + else() + message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}") + endif() + + # Workaround: Re-run CMake compiler ABI detection after ABI flags are set. + # + # Problem: CMake performs compiler checks at an early stage during + # toolchain.cmake processing. At this early stage, response files are not yet + # ready, which causes CMake paths (e.g., CMAKE__IMPLICIT_LINK_DIRECTORIES) + # to be incorrectly determined. + # + # Solution: Re-run the ABI detection after ABI flags are present to correctly + # determine these paths. + # + # Note: If the CMake API changes, this solution may need to be revised. + set(lang_ext_pairs "C|c" "CXX|cpp") + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + foreach(lang_ext ${lang_ext_pairs}) + string(REPLACE "|" ";" lang_ext_parts ${lang_ext}) + list(GET lang_ext_parts 0 lang) + list(GET lang_ext_parts 1 ext) + if(DEFINED CMAKE_${lang}_ABI_COMPILED) + unset(CMAKE_${lang}_ABI_COMPILED) + cmake_determine_compiler_abi(${lang} ${CMAKE_ROOT}/Modules/CMake${lang}CompilerABI.${ext}) + endif() + endforeach() +endif() diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index 1194687d0b0..ecf09dc7f0b 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -884,13 +884,6 @@ macro(project project_name) unset(idf_target) endif() - - if(CONFIG_LIBC_PICOLIBC) - idf_build_set_property(C_COMPILE_OPTIONS "-specs=picolibc.specs" APPEND) - idf_build_set_property(CXX_COMPILE_OPTIONS "-specs=picolibcpp.specs" APPEND) - idf_build_set_property(LINK_OPTIONS "-specs=picolibc.specs" APPEND) - endif() - set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${mapfile}" "${project_elf_src}") diff --git a/tools/cmake/targets.cmake b/tools/cmake/targets.cmake index e4c3f195b14..aa4c85c0e21 100644 --- a/tools/cmake/targets.cmake +++ b/tools/cmake/targets.cmake @@ -1,3 +1,4 @@ +include(${CMAKE_CURRENT_LIST_DIR}/toolchain_flags.cmake) # # Get target from single sdkconfig file # @@ -71,7 +72,7 @@ endfunction() # Set the target used for the standard project build. # macro(__target_init config_file) - # Input is IDF_TARGET environement variable + # Input is IDF_TARGET environment variable set(env_idf_target $ENV{IDF_TARGET}) if(NOT env_idf_target) @@ -129,30 +130,30 @@ macro(__target_set_toolchain) set(env_idf_toolchain $ENV{IDF_TOOLCHAIN}) if(NOT env_idf_toolchain) # IDF_TOOLCHAIN not set in environment, see if it is set in cache - if(IDF_TOOLCHAIN) - set(env_idf_toolchain ${IDF_TOOLCHAIN}) - else() - set(env_idf_toolchain gcc) - endif() - elseif(DEFINED CACHE{IDF_TOOLCHAIN}) - # IDF_TOOLCHAIN set both in environment and in cache, must be the same - if(NOT $CACHE{IDF_TOOLCHAIN} STREQUAL ${env_idf_toolchain}) - message(FATAL_ERROR " IDF_TOOLCHAIN '$CACHE{IDF_TOOLCHAIN}' in CMake cache does not match" - " currently selected IDF_TOOLCHAIN '${env_idf_toolchain}'. To change the toolchain, clear" - " the build directory and sdkconfig file, and build the project again.") + set(env_idf_toolchain ${IDF_TOOLCHAIN}) + if(NOT env_idf_toolchain) + set(env_idf_toolchain "gcc") endif() endif() - # Finally, set IDF_TOOLCHAIN in cache - set(IDF_TOOLCHAIN ${env_idf_toolchain} CACHE STRING "IDF Build Toolchain Type") + if(DEFINED CACHE{IDF_TOOLCHAIN} AND NOT "$CACHE{IDF_TOOLCHAIN}" STREQUAL "${env_idf_toolchain}") + # IDF_TOOLCHAIN set both in environment and in cache, must be the same + message(FATAL_ERROR " IDF_TOOLCHAIN '$CACHE{IDF_TOOLCHAIN}' in CMake cache does not match" + " currently selected IDF_TOOLCHAIN '${env_idf_toolchain}'. To change the toolchain, clear" + " the build directory and sdkconfig file, and build the project again.") + endif() if(${env_idf_toolchain} STREQUAL "clang") - set(toolchain_type "clang-") + # TODO IDF-14338: remove the line below since it will be set in toolchain.cmake + set(IDF_TOOLCHAIN ${env_idf_toolchain} CACHE STRING "IDF Build Toolchain Type") + set(toolchain_filename "toolchain-clang-${IDF_TARGET}.cmake") + else() + set(toolchain_filename "toolchain-${IDF_TARGET}.cmake") endif() # Check if selected target is consistent with toolchain file in CMake cache if(DEFINED CMAKE_TOOLCHAIN_FILE) - string(FIND "${CMAKE_TOOLCHAIN_FILE}" "-${toolchain_type}${IDF_TARGET}.cmake" found) + string(FIND "${CMAKE_TOOLCHAIN_FILE}" "${toolchain_filename}" found) if(${found} EQUAL -1) get_filename_component(toolchain "${CMAKE_TOOLCHAIN_FILE}" NAME_WE) message(FATAL_ERROR " CMAKE_TOOLCHAIN_FILE '${toolchain}'" @@ -162,11 +163,9 @@ macro(__target_set_toolchain) endif() endif() - # First try to load the toolchain file from the tools/cmake/directory of IDF - set(toolchain_file_global ${idf_path}/tools/cmake/toolchain-${toolchain_type}${IDF_TARGET}.cmake) - if(EXISTS ${toolchain_file_global}) - set(CMAKE_TOOLCHAIN_FILE ${toolchain_file_global}) - else() - message(FATAL_ERROR "Toolchain file ${toolchain_file_global} not found") + # Check if generated toolchain filepath is correct + set(CMAKE_TOOLCHAIN_FILE "${idf_path}/tools/cmake/${toolchain_filename}") + if(NOT EXISTS ${CMAKE_TOOLCHAIN_FILE}) + message(FATAL_ERROR "Toolchain file ${CMAKE_TOOLCHAIN_FILE} not found") endif() endmacro() diff --git a/tools/cmake/toolchain-esp32.cmake b/tools/cmake/toolchain-esp32.cmake index 5bf1acefaa7..8c1e461e2e4 100644 --- a/tools/cmake/toolchain-esp32.cmake +++ b/tools/cmake/toolchain-esp32.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER xtensa-esp32-elf-gcc) -set(CMAKE_CXX_COMPILER xtensa-esp32-elf-g++) -set(CMAKE_ASM_COMPILER xtensa-esp32-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32-elf-) - -remove_duplicated_flags("-mlongcalls -Wno-frame-address \ - -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \ - -fno-builtin-stpcpy -fno-builtin-strncpy \ - ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-mlongcalls -Wno-frame-address \ - -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \ - -fno-builtin-stpcpy -fno-builtin-strncpy \ - ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) -remove_duplicated_flags("-mlongcalls ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE) -remove_duplicated_flags("-nostartfiles ${CMAKE_EXE_LINKER_FLAGS}" UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c2.cmake b/tools/cmake/toolchain-esp32c2.cmake index d3a8b43dacb..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32c2.cmake +++ b/tools/cmake/toolchain-esp32c2.cmake @@ -1,17 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imc_zicsr_zifencei ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imc_zicsr_zifencei ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imc_zicsr_zifencei ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c3.cmake b/tools/cmake/toolchain-esp32c3.cmake index e263a82e475..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32c3.cmake +++ b/tools/cmake/toolchain-esp32c3.cmake @@ -1,19 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imc_zicsr_zifencei ${CMAKE_C_FLAGS}" - UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imc_zicsr_zifencei ${CMAKE_CXX_FLAGS}" - UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imc_zicsr_zifencei ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c5.cmake b/tools/cmake/toolchain-esp32c5.cmake index d0622555a5d..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32c5.cmake +++ b/tools/cmake/toolchain-esp32c5.cmake @@ -1,17 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imac_zicsr_zifencei ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c6.cmake b/tools/cmake/toolchain-esp32c6.cmake index d0622555a5d..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32c6.cmake +++ b/tools/cmake/toolchain-esp32c6.cmake @@ -1,17 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imac_zicsr_zifencei ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32c61.cmake b/tools/cmake/toolchain-esp32c61.cmake index d0622555a5d..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32c61.cmake +++ b/tools/cmake/toolchain-esp32c61.cmake @@ -1,17 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imac_zicsr_zifencei ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32h2.cmake b/tools/cmake/toolchain-esp32h2.cmake index d0622555a5d..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32h2.cmake +++ b/tools/cmake/toolchain-esp32h2.cmake @@ -1,17 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imac_zicsr_zifencei ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32h21.cmake b/tools/cmake/toolchain-esp32h21.cmake index 6415daa59b7..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32h21.cmake +++ b/tools/cmake/toolchain-esp32h21.cmake @@ -1,18 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imac_zicsr_zifencei ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imac_zicsr_zifencei --specs=nosys.specs \ - ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32h4.cmake b/tools/cmake/toolchain-esp32h4.cmake index c768ed0c754..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32h4.cmake +++ b/tools/cmake/toolchain-esp32h4.cmake @@ -1,20 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imafc_zicsr_zifencei -mabi=ilp32f ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imafc_zicsr_zifencei -mabi=ilp32f ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imafc_zicsr_zifencei -mabi=ilp32f ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imafc_zicsr_zifencei -mabi=ilp32f --specs=nosys.specs \ - ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32p4.cmake b/tools/cmake/toolchain-esp32p4.cmake index b46731a89d7..9833188d7db 100644 --- a/tools/cmake/toolchain-esp32p4.cmake +++ b/tools/cmake/toolchain-esp32p4.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER riscv32-esp-elf-gcc) -set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) -set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) - -remove_duplicated_flags("-march=rv32imafc_zicsr_zifencei_xesploop_xespv -mabi=ilp32f ${CMAKE_C_FLAGS}" - UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imafc_zicsr_zifencei_xesploop_xespv -mabi=ilp32f ${CMAKE_CXX_FLAGS}" - UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) -remove_duplicated_flags("-march=rv32imafc_zicsr_zifencei_xesploop_xespv -mabi=ilp32f ${CMAKE_ASM_FLAGS}" - UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "Asm Compiler Base Flags" FORCE) - -remove_duplicated_flags("-nostartfiles -march=rv32imafc_zicsr_zifencei_xesploop_xespv -mabi=ilp32f \ - ${CMAKE_EXE_LINKER_FLAGS}" - UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32s2.cmake b/tools/cmake/toolchain-esp32s2.cmake index 77b71113d97..74922e28dd4 100644 --- a/tools/cmake/toolchain-esp32s2.cmake +++ b/tools/cmake/toolchain-esp32s2.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER xtensa-esp32s2-elf-gcc) -set(CMAKE_CXX_COMPILER xtensa-esp32s2-elf-g++) -set(CMAKE_ASM_COMPILER xtensa-esp32s2-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32s2-elf-) - -remove_duplicated_flags("-mlongcalls \ - -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \ - -fno-builtin-stpcpy -fno-builtin-strncpy \ - ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-mlongcalls \ - -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \ - -fno-builtin-stpcpy -fno-builtin-strncpy \ - ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) -remove_duplicated_flags("-mlongcalls ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE) -remove_duplicated_flags("-nostartfiles ${CMAKE_EXE_LINKER_FLAGS}" UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain-esp32s3.cmake b/tools/cmake/toolchain-esp32s3.cmake index f3ba9f798be..2deb82c2aca 100644 --- a/tools/cmake/toolchain-esp32s3.cmake +++ b/tools/cmake/toolchain-esp32s3.cmake @@ -1,23 +1,2 @@ -include($ENV{IDF_PATH}/tools/cmake/utilities.cmake) - -set(CMAKE_SYSTEM_NAME Generic) - -set(CMAKE_C_COMPILER xtensa-esp32s3-elf-gcc) -set(CMAKE_CXX_COMPILER xtensa-esp32s3-elf-g++) -set(CMAKE_ASM_COMPILER xtensa-esp32s3-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX xtensa-esp32s3-elf-) - -remove_duplicated_flags("-mlongcalls \ - -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \ - -fno-builtin-stpcpy -fno-builtin-strncpy \ - ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) -set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) -remove_duplicated_flags("-mlongcalls \ - -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero \ - -fno-builtin-stpcpy -fno-builtin-strncpy \ - ${CMAKE_CXX_FLAGS}" UNIQ_CMAKE_CXX_FLAGS) -set(CMAKE_CXX_FLAGS "${UNIQ_CMAKE_CXX_FLAGS}" CACHE STRING "C++ Compiler Base Flags" FORCE) -remove_duplicated_flags("-mlongcalls ${CMAKE_ASM_FLAGS}" UNIQ_CMAKE_ASM_FLAGS) -set(CMAKE_ASM_FLAGS "${UNIQ_CMAKE_ASM_FLAGS}" CACHE STRING "ASM Compiler Base Flags" FORCE) -remove_duplicated_flags("-nostartfiles ${CMAKE_EXE_LINKER_FLAGS}" UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS) -set(CMAKE_EXE_LINKER_FLAGS "${UNIQ_CMAKE_SAFE_EXE_LINKER_FLAGS}" CACHE STRING "Linker Base Flags" FORCE) +include($ENV{IDF_PATH}/tools/cmake/toolchain.cmake) diff --git a/tools/cmake/toolchain.cmake b/tools/cmake/toolchain.cmake new file mode 100644 index 00000000000..db1f80181b0 --- /dev/null +++ b/tools/cmake/toolchain.cmake @@ -0,0 +1,85 @@ +include(${CMAKE_CURRENT_LIST_DIR}/toolchain_flags.cmake) + +if(NOT CMAKE_PARENT_LIST_FILE) + message(FATAL_ERROR "toolchain.cmake cannot be used standalone (use chip-specific toolchain file instead)") +endif() + +# Paths normalization +get_filename_component(_idf_toolchain_dir "$ENV{IDF_PATH}/tools/cmake" REALPATH) +file(TO_CMAKE_PATH "${_idf_toolchain_dir}" _idf_toolchain_dir) + +get_filename_component(_toolchain_filename "${CMAKE_TOOLCHAIN_FILE}" NAME) +get_filename_component(_current_toolchain_dir "${CMAKE_TOOLCHAIN_FILE}" DIRECTORY REALPATH) +file(TO_CMAKE_PATH "${_current_toolchain_dir}" _current_toolchain_dir) + +set(CMAKE_SYSTEM_NAME Generic) + +# Set compiler tools according to the toolchain type +string(FIND "${_toolchain_filename}" "clang" found_clang) +if(NOT found_clang EQUAL -1) + set(IDF_TOOLCHAIN "clang" CACHE STRING "IDF Build Toolchain Type" FORCE) + + set(CMAKE_C_COMPILER clang) + set(CMAKE_CXX_COMPILER clang++) + set(CMAKE_ASM_COMPILER clang) + set(CMAKE_LINKER ${_CMAKE_TOOLCHAIN_PREFIX}ld) + set(CMAKE_AR llvm-ar) + set(CMAKE_RANLIB llvm-ranlib) + set(CMAKE_OBJDUMP ${_CMAKE_TOOLCHAIN_PREFIX}objdump) +else() + set(IDF_TOOLCHAIN "gcc" CACHE STRING "IDF Build Toolchain Type" FORCE) + + set(CMAKE_C_COMPILER ${_CMAKE_TOOLCHAIN_PREFIX}gcc) + set(CMAKE_CXX_COMPILER ${_CMAKE_TOOLCHAIN_PREFIX}g++) + set(CMAKE_ASM_COMPILER ${_CMAKE_TOOLCHAIN_PREFIX}gcc) +endif() + +# Handle different execution contexts for the toolchain file. +# CMake may execute this toolchain file in different contexts: +# +# 1. First execution (IDF project build): +# When CMAKE_TOOLCHAIN_FILE points to IDF sources, the toolchain file is +# executed for the main project. In this case, we create the response files +# directory in the build directory, copy the toolchain file there, initialize +# the response files, and update CMAKE_TOOLCHAIN_FILE to point to the copy. +# +# 2. Subsequent executions (External project builds): +# When CMAKE_TOOLCHAIN_FILE points to a copied toolchain file (from a +# previous root project build), the response files already exist in the same +# directory as the toolchain file. We simply set IDF_TOOLCHAIN_BUILD_DIR to +# point to that existing directory. +if(_idf_toolchain_dir STREQUAL _current_toolchain_dir) + set(IDF_TOOLCHAIN_BUILD_DIR "${CMAKE_BINARY_DIR}/toolchain" + CACHE PATH "Path to toolchain build directory containing response files and toolchain file copy" FORCE) + + # Copy toolchain file into the build directory and update CMAKE_TOOLCHAIN_FILE + # to point to the copy. This approach allows us to avoid worrying about different + # CMAKE_BINARY_DIR values between base IDF-project builds and external projects. + # For external project builds, compiler response files are located in the same + # directory as CMAKE_TOOLCHAIN_FILE, making them easy to find. + file(MAKE_DIRECTORY "${IDF_TOOLCHAIN_BUILD_DIR}") + file(COPY "${CMAKE_TOOLCHAIN_FILE}" DESTINATION "${IDF_TOOLCHAIN_BUILD_DIR}") + set(CMAKE_TOOLCHAIN_FILE "${IDF_TOOLCHAIN_BUILD_DIR}/${_toolchain_filename}") + + # Create response files before CMake performs compiler checks. + # These files are required for the compiler detection process to succeed. + # The files are created even when the flag variables are empty, ensuring + # they exist when referenced by CMAKE_*_FLAGS variables below. + idf_toolchain_add_flags(C_COMPILE_OPTIONS "${CMAKE_C_FLAGS}" + CXX_COMPILE_OPTIONS "${CMAKE_CXX_FLAGS}" + ASM_COMPILE_OPTIONS "${CMAKE_ASM_FLAGS}" + LINK_OPTIONS "${CMAKE_EXE_LINKER_FLAGS}") +else() + set(IDF_TOOLCHAIN_BUILD_DIR "${_current_toolchain_dir}" + CACHE PATH "Path to toolchain build directory containing response files and toolchain file copy" FORCE) +endif() + +# Configure CMake to use response files for compiler and linker flags. +# Some compilation options enabled by IDF configuration options are not yet +# defined at this very early CMake stage (toolchain.cmake execution). Response +# files allow these flags to be dynamically updated during the CMake configuration +# phase, after the options become available. +set(CMAKE_C_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/cflags\"" CACHE STRING "C Compiler Base Flags" FORCE) +set(CMAKE_CXX_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/cxxflags\"" CACHE STRING "C++ Compiler Base Flags" FORCE) +set(CMAKE_ASM_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/asmflags\"" CACHE STRING "Asm Compiler Base Flags" FORCE) +set(CMAKE_EXE_LINKER_FLAGS "@\"${IDF_TOOLCHAIN_BUILD_DIR}/ldflags\"" CACHE STRING "Linker Base Flags" FORCE) diff --git a/tools/cmake/toolchain_flags.cmake b/tools/cmake/toolchain_flags.cmake new file mode 100644 index 00000000000..682e4e2602b --- /dev/null +++ b/tools/cmake/toolchain_flags.cmake @@ -0,0 +1,157 @@ +# Map option variable names to their corresponding file lists +set(_IDF_TOOLCHAIN_OPTION_MAPPINGS + "COMPILE_OPTIONS|cflags:cxxflags:asmflags" + "C_COMPILE_OPTIONS|cflags" + "CXX_COMPILE_OPTIONS|cxxflags" + "ASM_COMPILE_OPTIONS|asmflags" + "LINK_OPTIONS|ldflags" +) + +# Extract keywords from mappings (drop substring after "|") +set(_IDF_TOOLCHAIN_MULTI_VALUE_KEYWORDS "") +foreach(mapping ${_IDF_TOOLCHAIN_OPTION_MAPPINGS}) + string(REGEX REPLACE "\\|.*" "" keyword "${mapping}") + list(APPEND _IDF_TOOLCHAIN_MULTI_VALUE_KEYWORDS "${keyword}") +endforeach() + +# Helper macro to process toolchain flag options based on mappings +# Uses macro instead of function to access parent scope variables directly +# operation: "add" or "remove" +macro(_process_toolchain_flag_options) + cmake_parse_arguments(PARSE_ARGV 0 "" "" "" "${_IDF_TOOLCHAIN_MULTI_VALUE_KEYWORDS}") + + if(NOT EXISTS "${IDF_TOOLCHAIN_BUILD_DIR}") + message(FATAL_ERROR "Toolchain directory does not exist: ${IDF_TOOLCHAIN_BUILD_DIR}") + endif() + + foreach(mapping ${_IDF_TOOLCHAIN_OPTION_MAPPINGS}) + string(REPLACE "|" ";" mapping_list ${mapping}) + # Extract option variable name and add underscore prefix + list(GET mapping_list 0 option_var) + set(option_var "_${option_var}") + + # Extract file list for this option variable + list(GET mapping_list 1 files) + string(REPLACE ":" ";" files ${files}) + + # Process flags based on calling function: add or remove + if("${CMAKE_CURRENT_FUNCTION}" MATCHES "add_flags" AND DEFINED ${option_var}) + _add_flags_to_files("${files}" "${${option_var}}") + endif() + if("${CMAKE_CURRENT_FUNCTION}" MATCHES "remove_flags" AND ${option_var}) + _remove_flags_from_files("${files}" "${${option_var}}") + endif() + endforeach() +endmacro() + +# Helper function to remove flags matching patterns from specific files +function(_remove_flags_from_files files patterns) + foreach(file ${files}) + set(file_path "${IDF_TOOLCHAIN_BUILD_DIR}/${file}") + + if(EXISTS "${file_path}") + file(STRINGS "${file_path}" existing_lines) + else() + set(existing_lines "") + endif() + + file(WRITE "${file_path}" "") + foreach(line ${existing_lines}) + set(should_keep TRUE) + foreach(pattern ${patterns}) + if("${line}" MATCHES "${pattern}") + set(should_keep FALSE) + break() + endif() + endforeach() + if(should_keep) + file(APPEND "${file_path}" "${line}\n") + endif() + endforeach() + endforeach() +endfunction() + +# Helper function to add flags to specific files +function(_add_flags_to_files files flags) + foreach(file ${files}) + set(file_path "${IDF_TOOLCHAIN_BUILD_DIR}/${file}") + + if(EXISTS "${file_path}") + file(STRINGS "${file_path}" existing_lines) + else() + set(existing_lines "") + endif() + + # Split flags string using regex to respect quotes. + # Matches: double-quoted strings, single-quoted strings, or unquoted space-delimited tokens. + # + # TODO IDF-14467: + # Currently, paired linker flags are not properly handled when filtering. + # The regex-based splitting treats each flag independently, which breaks + # flag pairs that must be kept together. Future enhancement should support + # the following paired flag constructs: + # - --start-group ... --end-group + # - --push-state ... --pop-state + # - --whole-archive ... --no-whole-archive + # - --as-needed ... --no-as-needed + # - --push-section ... --pop-section + string(REGEX MATCHALL "([^\\s\"']*(\"[^\"]*\"|'[^']*')|\"[^\"]*\"|'[^']*'|[^ \"']+)" flags "${flags}") + + file(WRITE "${file_path}" "") + foreach(line ${existing_lines}) + set(should_keep TRUE) + foreach(flag ${flags}) + if("${line}" STREQUAL "${flag}") + set(should_keep FALSE) + break() + endif() + endforeach() + if(should_keep) + file(APPEND "${file_path}" "${line}\n") + endif() + endforeach() + + foreach(flag ${flags}) + # Skip flags that contain IDF_TOOLCHAIN_BUILD_DIR substring + # to avoid recursion + string(FIND "${flag}" "${IDF_TOOLCHAIN_BUILD_DIR}" found_pos) + if(found_pos EQUAL -1) + file(APPEND "${file_path}" "${flag}\n") + endif() + endforeach() + endforeach() +endfunction() + +# idf_toolchain_add_flags +# +# @brief Add compiler or linker flags to the toolchain configuration files. +# +# This function adds flags to the appropriate toolchain response files (cflags, cxxflags, +# asmflags, or ldflags) in the IDF_TOOLCHAIN_BUILD_DIR directory. Duplicate flags +# are automatically removed before adding new ones. +# +# @param[in, optional] COMPILE_OPTIONS (multivalue) flags to add to C, C++, and ASM +# compilation. Applied to cflags, cxxflags, and asmflags files. +# @param[in, optional] C_COMPILE_OPTIONS (multivalue) flags to add to C compilation only. +# Applied to cflags file. +# @param[in, optional] CXX_COMPILE_OPTIONS (multivalue) flags to add to C++ compilation only. +# Applied to cxxflags file. +# @param[in, optional] ASM_COMPILE_OPTIONS (multivalue) flags to add to ASM compilation only. +# Applied to asmflags file. +# @param[in, optional] LINK_OPTIONS (multivalue) flags to add to linking. +# Applied to ldflags file. +# +# @note Multiple keyword arguments can be specified in a single call. +# @note Flags are deduplicated - if a flag already exists in the file, it will be +# removed before adding the new one to ensure no duplicates. +# +# Example: +# idf_toolchain_add_flags(COMPILE_OPTIONS "-Wall" "-Wextra") +# idf_toolchain_add_flags(C_COMPILE_OPTIONS "-std=c99" LINK_OPTIONS "-Wl,--gc-sections") +function(idf_toolchain_add_flags) + _process_toolchain_flag_options() +endfunction() + +function(idf_toolchain_remove_flags) + _process_toolchain_flag_options() +endfunction() From 0b3929d0d99d1564029f2e97ff2ad89204553198 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Sat, 4 Oct 2025 19:54:59 +0700 Subject: [PATCH 03/18] feat(esp_libc): add full support for picolibc --- CMakeLists.txt | 21 +++++-- Kconfig | 1 - .../bt/common/osi/include/osi/pkt_queue.h | 1 + components/bt/common/tinycrypt/src/ecc.c | 1 + components/esp_hw_support/include/esp_cpu.h | 31 ++++++++++ components/esp_rom/CMakeLists.txt | 2 +- .../esp_rom/esp32/ld/esp32.rom.libc-funcs.ld | 15 +---- .../esp32/ld/esp32.rom.newlib-reent-funcs.ld | 15 ++++- .../esp_rom/esp32c2/ld/esp32c2.rom.libc.ld | 13 ---- .../esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld | 15 ++++- .../esp_rom/esp32c3/ld/esp32c3.rom.libc.ld | 13 ---- .../esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld | 15 ++++- .../esp_rom/esp32c5/ld/esp32c5.rom.libc.ld | 13 ---- .../esp_rom/esp32c5/ld/esp32c5.rom.newlib.ld | 13 ++++ .../esp_rom/esp32c6/ld/esp32c6.rom.libc.ld | 13 ---- .../esp_rom/esp32c6/ld/esp32c6.rom.newlib.ld | 15 ++++- .../esp_rom/esp32c61/ld/esp32c61.rom.libc.ld | 13 ---- .../esp32c61/ld/esp32c61.rom.newlib.ld | 15 ++++- .../esp_rom/esp32h2/ld/esp32h2.rom.libc.ld | 13 ---- .../esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld | 15 ++++- .../esp_rom/esp32h21/ld/esp32h21.rom.libc.ld | 13 ---- .../esp32h21/ld/esp32h21.rom.newlib.ld | 13 ++++ .../esp_rom/esp32p4/ld/esp32p4.rom.libc.ld | 13 ---- .../esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld | 13 ++++ .../esp32s2/ld/esp32s2.rom.libc-funcs.ld | 14 +---- .../ld/esp32s2.rom.newlib-reent-funcs.ld | 14 ++++- .../esp_rom/esp32s3/ld/esp32s3.rom.libc.ld | 15 +---- .../esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld | 15 ++++- components/esp_system/ld/elf_misc.ld.in | 2 + components/esp_system/ld/esp32/sections.ld.in | 12 ++++ .../esp_system/ld/esp32c2/sections.ld.in | 30 +++++++-- .../esp_system/ld/esp32c3/sections.ld.in | 30 +++++++-- .../esp_system/ld/esp32c5/sections.ld.in | 48 ++++++++++----- .../esp_system/ld/esp32c6/sections.ld.in | 30 +++++++-- .../esp_system/ld/esp32c61/sections.ld.in | 48 ++++++++++----- .../esp_system/ld/esp32h2/sections.ld.in | 30 +++++++-- .../esp_system/ld/esp32h21/sections.ld.in | 30 +++++++-- .../esp_system/ld/esp32h4/sections.ld.in | 30 +++++++-- .../esp_system/ld/esp32p4/sections.ld.in | 48 ++++++++++----- .../esp_system/ld/esp32p4/sections.rev3.ld.in | 50 ++++++++++----- .../esp_system/ld/esp32s2/sections.ld.in | 12 ++++ .../esp_system/ld/esp32s3/sections.ld.in | 12 ++++ components/esp_system/ld/ld.common | 11 ++++ components/esp_system/port/cpu_start.c | 23 +++++++ .../hal/platform_port/include/hal/assert.h | 18 +++++- .../heap_tests/main/test_heap_trace.c | 17 ++++-- .../lwip/port/esp32xx/include/arch/cc.h | 10 ++- components/lwip/test_apps/main/lwip_test.c | 1 + components/newlib/CMakeLists.txt | 6 +- components/newlib/Kconfig | 35 ++++++++++- components/newlib/platform_include/stdio.h | 14 ++++- .../newlib/platform_include/stdio_ext.h | 4 +- .../newlib/platform_include/sys/cdefs.h | 12 ++++ .../newlib/platform_include/sys/fcntl.h | 13 ++++ components/newlib/platform_include/sys/time.h | 13 +++- .../newlib/platform_include/sys/unistd.h | 7 ++- components/newlib/project_include.cmake | 2 + components/newlib/sbom.yml | 12 ++-- components/newlib/sbom_newlibc.yml | 10 +++ components/newlib/sbom_picolibc.yml | 6 ++ components/newlib/src/locks.c | 50 +++++++-------- components/newlib/src/picolibc/errno.c | 22 +++++++ components/newlib/src/picolibc/getreent.c | 19 ++++++ .../newlib/src/picolibc/picolibc_init.c | 55 ++++++++--------- components/newlib/src/syscalls.c | 4 ++ components/riscv/include/riscv/rv_utils.h | 12 ++++ components/sdmmc/include/sd_protocol_defs.h | 1 + .../esp32p4/register/hw_ver3/soc/pmu_struct.h | 1 + components/soc/project_include.cmake | 39 +++--------- components/tcp_transport/transport_ssl.c | 1 + components/ulp/esp32ulp_mapgen.py | 61 ++++++++++++------- components/vfs/test_apps/main/test_vfs_fd.c | 1 + components/vfs/test_apps/main/test_vfs_lwip.c | 1 + .../vfs/test_apps/main/test_vfs_select.c | 1 + components/vfs/vfs.c | 1 + components/xtensa/include/xt_utils.h | 14 ++++- docs/en/api-guides/stdio.rst | 15 ++++- .../network/simple_sniffer/main/cmd_sniffer.c | 1 + .../deep_sleep/main/esp_ot_sleepy_device.c | 1 + .../fatfsgen/main/fatfsgen_example_main.c | 1 + tools/cmake/toolchain_flags.cmake | 25 ++++++++ .../fatfsgen/main/fatfsgen_example_main.c | 1 + 82 files changed, 934 insertions(+), 382 deletions(-) create mode 100644 components/newlib/platform_include/sys/cdefs.h create mode 100644 components/newlib/platform_include/sys/fcntl.h create mode 100644 components/newlib/sbom_newlibc.yml create mode 100644 components/newlib/sbom_picolibc.yml create mode 100644 components/newlib/src/picolibc/errno.c create mode 100644 components/newlib/src/picolibc/getreent.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d6188f7755..1af1b8556f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,11 +74,22 @@ else() list(APPEND cxx_compile_options "-fno-exceptions") endif() -if(CONFIG_COMPILER_CXX_RTTI) - list(APPEND cxx_compile_options "-frtti") -else() - list(APPEND cxx_compile_options "-fno-rtti") - list(APPEND link_options "-fno-rtti") # used to invoke correct multilib variant (no-rtti) during linking +if(CONFIG_IDF_TOOLCHAIN_GCC) + if(CONFIG_COMPILER_CXX_RTTI) + idf_toolchain_remove_flags(CXX_COMPILE_OPTIONS "-fno-rtti" + LINK_OPTIONS "-fno-rtti") + else() + idf_toolchain_add_flags(CXX_COMPILE_OPTIONS "-fno-rtti" + LINK_OPTIONS "-fno-rtti") + endif() + idf_toolchain_rerun_abi_detection() +else() # TODO IDF-14338 + if(CONFIG_COMPILER_CXX_RTTI) + list(APPEND cxx_compile_options "-frtti") + else() + list(APPEND cxx_compile_options "-fno-rtti") + list(APPEND link_options "-fno-rtti") # used to invoke correct multilib variant (no-rtti) during linking + endif() endif() if(CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS) diff --git a/Kconfig b/Kconfig index 8fa992054ef..3fa8988472f 100644 --- a/Kconfig +++ b/Kconfig @@ -706,4 +706,3 @@ mainmenu "Espressif IoT Development Framework Configuration" - CONFIG_ESP_WIFI_EAP_TLS1_3 - CONFIG_ESP_WIFI_ENABLE_ROAMING_APP - CONFIG_USB_HOST_EXT_PORT_RESET_ATTEMPTS - - CONFIG_LIBC_PICOLIBC diff --git a/components/bt/common/osi/include/osi/pkt_queue.h b/components/bt/common/osi/include/osi/pkt_queue.h index 96277c3e182..38eff71ffa1 100644 --- a/components/bt/common/osi/include/osi/pkt_queue.h +++ b/components/bt/common/osi/include/osi/pkt_queue.h @@ -10,6 +10,7 @@ #include "sys/queue.h" #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/components/bt/common/tinycrypt/src/ecc.c b/components/bt/common/tinycrypt/src/ecc.c index 1027c9a293c..5e8495d31a6 100644 --- a/components/bt/common/tinycrypt/src/ecc.c +++ b/components/bt/common/tinycrypt/src/ecc.c @@ -58,6 +58,7 @@ #include #include +#include #include #include diff --git a/components/esp_hw_support/include/esp_cpu.h b/components/esp_hw_support/include/esp_cpu.h index cbecbafff64..391c17db1a7 100644 --- a/components/esp_hw_support/include/esp_cpu.h +++ b/components/esp_hw_support/include/esp_cpu.h @@ -224,6 +224,37 @@ FORCE_INLINE_ATTR __attribute__((pure)) void *esp_cpu_pc_to_addr(uint32_t pc) #endif } +/** + * @brief Set the current CPU core's thread pointer + * + * Sets the thread pointer register to the given value. + * + * @param threadptr Pointer to the thread-local storage area + */ +FORCE_INLINE_ATTR void esp_cpu_set_threadptr(void * threadptr) +{ +#ifdef __XTENSA__ + xt_utils_set_threadptr(threadptr); +#else + rv_utils_set_threadptr(threadptr); +#endif +} + +/** + * @brief Get the current CPU core's thread pointer + * + * @return thread pointer register value + */ +FORCE_INLINE_ATTR void *esp_cpu_get_threadptr(void) +{ +#ifdef __XTENSA__ + return xt_utils_get_threadptr(); +#else + return rv_utils_get_threadptr(); +#endif +} + + /* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index e2c1801928b..8faf53431af 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -144,7 +144,7 @@ endif() if(ESP_TEE_BUILD) rom_linker_script("heap") - if(CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT) + if(CONFIG_LIBC_NEWLIB AND CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT) rom_linker_script("newlib-nano") endif() endif() diff --git a/components/esp_rom/esp32/ld/esp32.rom.libc-funcs.ld b/components/esp_rom/esp32/ld/esp32.rom.libc-funcs.ld index 506c0f77535..662c7a0db50 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.libc-funcs.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.libc-funcs.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,18 +22,12 @@ bzero = 0x4000c1f4; div = 0x40056348; __dummy_lock = 0x4000c728; __dummy_lock_try = 0x4000c730; -isalnum = 0x40000f04; -isalpha = 0x40000f18; isascii = 0x4000c20c; isblank = 0x40000f2c; iscntrl = 0x40000f50; -isdigit = 0x40000f64; isgraph = 0x40000f94; -islower = 0x40000f78; isprint = 0x40000fa8; ispunct = 0x40000fc0; -isspace = 0x40000fd4; -isupper = 0x40000fe8; __itoa = 0x40056678; itoa = 0x400566b4; labs = 0x40056370; @@ -49,19 +43,15 @@ memset = 0x4000c44c; qsort = 0x40056424; __sccl = 0x4000c498; setjmp = 0x40056268; -strcasecmp = 0x400011cc; strcasestr = 0x40001210; strcat = 0x4000c518; strchr = 0x4000c53c; strcmp = 0x40001274; -strcoll = 0x40001398; strcpy = 0x400013ac; strcspn = 0x4000c558; strlcat = 0x40001470; strlcpy = 0x4000c584; strlen = 0x400014c0; -strlwr = 0x40001524; -strncasecmp = 0x40001550; strncat = 0x4000c5c4; strncmp = 0x4000c5f4; strncpy = 0x400015d4; @@ -70,10 +60,7 @@ strrchr = 0x40001708; strsep = 0x40001734; strspn = 0x4000c648; strstr = 0x4000c674; -strupr = 0x4000174c; __submore = 0x40058f3c; toascii = 0x4000c720; -tolower = 0x40001868; -toupper = 0x40001884; __utoa = 0x400561f0; utoa = 0x40056258; diff --git a/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld b/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld index 49c49b19b2e..aa4f48f359b 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -59,3 +59,16 @@ __sinit_lock_release = 0x40001e2c; __env_lock = 0x40001fd4; __env_unlock = 0x40001fe0; _getenv_r = 0x40001fbc; +tolower = 0x40001868; +toupper = 0x40001884; +isalnum = 0x40000f04; +isalpha = 0x40000f18; +isdigit = 0x40000f64; +islower = 0x40000f78; +isspace = 0x40000fd4; +isupper = 0x40000fe8; +strcasecmp = 0x400011cc; +strcoll = 0x40001398; +strlwr = 0x40001524; +strncasecmp = 0x40001550; +strupr = 0x4000174c; diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.libc.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.libc.ld index 920da099829..7d90b649ce4 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.libc.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x400004a8; strstr = 0x400004ac; bzero = 0x400004b0; sbrk = 0x400004b8; -isalnum = 0x400004bc; -isalpha = 0x400004c0; isascii = 0x400004c4; isblank = 0x400004c8; iscntrl = 0x400004cc; -isdigit = 0x400004d0; -islower = 0x400004d4; isgraph = 0x400004d8; isprint = 0x400004dc; ispunct = 0x400004e0; -isspace = 0x400004e4; -isupper = 0x400004e8; -toupper = 0x400004ec; -tolower = 0x400004f0; toascii = 0x400004f4; memccpy = 0x400004f8; memchr = 0x400004fc; memrchr = 0x40000500; -strcasecmp = 0x40000504; strcasestr = 0x40000508; strcat = 0x4000050c; strchr = 0x40000514; strcspn = 0x40000518; -strcoll = 0x4000051c; strlcat = 0x40000520; strlcpy = 0x40000524; -strlwr = 0x40000528; -strncasecmp = 0x4000052c; strncat = 0x40000530; strnlen = 0x40000538; strrchr = 0x4000053c; strsep = 0x40000540; strspn = 0x40000544; strtok_r = 0x40000548; -strupr = 0x4000054c; longjmp = 0x40000550; setjmp = 0x40000554; abs = 0x40000558; diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld index a6963f86d01..f9eda11b4a7 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,3 +63,16 @@ puts = 0x4000065c; putc = 0x40000660; putchar = 0x40000664; __errno = 0x40000670; +toupper = 0x400004ec; +tolower = 0x400004f0; +isalnum = 0x400004bc; +isalpha = 0x400004c0; +isdigit = 0x400004d0; +islower = 0x400004d4; +isspace = 0x400004e4; +isupper = 0x400004e8; +strcasecmp = 0x40000504; +strcoll = 0x4000051c; +strlwr = 0x40000528; +strncasecmp = 0x4000052c; +strupr = 0x4000054c; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.libc.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.libc.ld index a7476cac1d6..f206243491b 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.libc.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x40000374; strstr = 0x40000378; bzero = 0x4000037c; sbrk = 0x40000384; -isalnum = 0x40000388; -isalpha = 0x4000038c; isascii = 0x40000390; isblank = 0x40000394; iscntrl = 0x40000398; -isdigit = 0x4000039c; -islower = 0x400003a0; isgraph = 0x400003a4; isprint = 0x400003a8; ispunct = 0x400003ac; -isspace = 0x400003b0; -isupper = 0x400003b4; -toupper = 0x400003b8; -tolower = 0x400003bc; toascii = 0x400003c0; memccpy = 0x400003c4; memchr = 0x400003c8; memrchr = 0x400003cc; -strcasecmp = 0x400003d0; strcasestr = 0x400003d4; strcat = 0x400003d8; strchr = 0x400003e0; strcspn = 0x400003e4; -strcoll = 0x400003e8; strlcat = 0x400003ec; strlcpy = 0x400003f0; -strlwr = 0x400003f4; -strncasecmp = 0x400003f8; strncat = 0x400003fc; strnlen = 0x40000404; strrchr = 0x40000408; strsep = 0x4000040c; strspn = 0x40000410; strtok_r = 0x40000414; -strupr = 0x40000418; longjmp = 0x4000041c; setjmp = 0x40000420; abs = 0x40000424; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld index 69e93fccd9c..2f3662e60c9 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,3 +35,16 @@ PROVIDE( _fwalk = 0x40000464 ); PROVIDE( _fwalk_reent = 0x40000468 ); PROVIDE( __swbuf_r = 0x40000474 ); __swbuf = 0x40000478; +toupper = 0x400003b8; +tolower = 0x400003bc; +isalnum = 0x40000388; +isalpha = 0x4000038c; +isdigit = 0x4000039c; +islower = 0x400003a0; +isspace = 0x400003b0; +isupper = 0x400003b4; +strcasecmp = 0x400003d0; +strcoll = 0x400003e8; +strlwr = 0x400003f4; +strncasecmp = 0x400003f8; +strupr = 0x40000418; diff --git a/components/esp_rom/esp32c5/ld/esp32c5.rom.libc.ld b/components/esp_rom/esp32c5/ld/esp32c5.rom.libc.ld index a7b1e8b03cb..ecdbff4f3a3 100644 --- a/components/esp_rom/esp32c5/ld/esp32c5.rom.libc.ld +++ b/components/esp_rom/esp32c5/ld/esp32c5.rom.libc.ld @@ -24,41 +24,28 @@ strlen = 0x400004d8; strstr = 0x400004dc; bzero = 0x400004e0; sbrk = 0x400004e8; -isalnum = 0x400004ec; -isalpha = 0x400004f0; isascii = 0x400004f4; isblank = 0x400004f8; iscntrl = 0x400004fc; -isdigit = 0x40000500; -islower = 0x40000504; isgraph = 0x40000508; isprint = 0x4000050c; ispunct = 0x40000510; -isspace = 0x40000514; -isupper = 0x40000518; -toupper = 0x4000051c; -tolower = 0x40000520; toascii = 0x40000524; memccpy = 0x40000528; memchr = 0x4000052c; memrchr = 0x40000530; -strcasecmp = 0x40000534; strcasestr = 0x40000538; strcat = 0x4000053c; strchr = 0x40000544; strcspn = 0x40000548; -strcoll = 0x4000054c; strlcat = 0x40000550; strlcpy = 0x40000554; -strlwr = 0x40000558; -strncasecmp = 0x4000055c; strncat = 0x40000560; strnlen = 0x40000568; strrchr = 0x4000056c; strsep = 0x40000570; strspn = 0x40000574; strtok_r = 0x40000578; -strupr = 0x4000057c; longjmp = 0x40000580; setjmp = 0x40000584; abs = 0x40000588; diff --git a/components/esp_rom/esp32c5/ld/esp32c5.rom.newlib.ld b/components/esp_rom/esp32c5/ld/esp32c5.rom.newlib.ld index 0a970172a72..24806f1995e 100644 --- a/components/esp_rom/esp32c5/ld/esp32c5.rom.newlib.ld +++ b/components/esp_rom/esp32c5/ld/esp32c5.rom.newlib.ld @@ -37,3 +37,16 @@ __swhatbuf_r = 0x400005d4; __swbuf_r = 0x400005d8; __swbuf = 0x400005dc; __swsetup_r = 0x400005e0; +toupper = 0x4000051c; +tolower = 0x40000520; +isalnum = 0x400004ec; +isalpha = 0x400004f0; +isdigit = 0x40000500; +islower = 0x40000504; +isspace = 0x40000514; +isupper = 0x40000518; +strcasecmp = 0x40000534; +strcoll = 0x4000054c; +strlwr = 0x40000558; +strncasecmp = 0x4000055c; +strupr = 0x4000057c; diff --git a/components/esp_rom/esp32c6/ld/esp32c6.rom.libc.ld b/components/esp_rom/esp32c6/ld/esp32c6.rom.libc.ld index 16c5b607108..4f3356731fd 100644 --- a/components/esp_rom/esp32c6/ld/esp32c6.rom.libc.ld +++ b/components/esp_rom/esp32c6/ld/esp32c6.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x400004c8; strstr = 0x400004cc; bzero = 0x400004d0; sbrk = 0x400004d8; -isalnum = 0x400004dc; -isalpha = 0x400004e0; isascii = 0x400004e4; isblank = 0x400004e8; iscntrl = 0x400004ec; -isdigit = 0x400004f0; -islower = 0x400004f4; isgraph = 0x400004f8; isprint = 0x400004fc; ispunct = 0x40000500; -isspace = 0x40000504; -isupper = 0x40000508; -toupper = 0x4000050c; -tolower = 0x40000510; toascii = 0x40000514; memccpy = 0x40000518; memchr = 0x4000051c; memrchr = 0x40000520; -strcasecmp = 0x40000524; strcasestr = 0x40000528; strcat = 0x4000052c; strchr = 0x40000534; strcspn = 0x40000538; -strcoll = 0x4000053c; strlcat = 0x40000540; strlcpy = 0x40000544; -strlwr = 0x40000548; -strncasecmp = 0x4000054c; strncat = 0x40000550; strnlen = 0x40000558; strrchr = 0x4000055c; strsep = 0x40000560; strspn = 0x40000564; strtok_r = 0x40000568; -strupr = 0x4000056c; longjmp = 0x40000570; setjmp = 0x40000574; abs = 0x40000578; diff --git a/components/esp_rom/esp32c6/ld/esp32c6.rom.newlib.ld b/components/esp_rom/esp32c6/ld/esp32c6.rom.newlib.ld index 2bae4792479..454a1779abf 100644 --- a/components/esp_rom/esp32c6/ld/esp32c6.rom.newlib.ld +++ b/components/esp_rom/esp32c6/ld/esp32c6.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,3 +39,16 @@ __swhatbuf_r = 0x400005c4; __swbuf_r = 0x400005c8; __swbuf = 0x400005cc; __swsetup_r = 0x400005d0; +toupper = 0x4000050c; +tolower = 0x40000510; +isalnum = 0x400004dc; +isalpha = 0x400004e0; +isdigit = 0x400004f0; +islower = 0x400004f4; +isspace = 0x40000504; +isupper = 0x40000508; +strcasecmp = 0x40000524; +strcoll = 0x4000053c; +strlwr = 0x40000548; +strncasecmp = 0x4000054c; +strupr = 0x4000056c; diff --git a/components/esp_rom/esp32c61/ld/esp32c61.rom.libc.ld b/components/esp_rom/esp32c61/ld/esp32c61.rom.libc.ld index 771fa2f0848..676cfcdf2c2 100644 --- a/components/esp_rom/esp32c61/ld/esp32c61.rom.libc.ld +++ b/components/esp_rom/esp32c61/ld/esp32c61.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x400004d8; strstr = 0x400004dc; bzero = 0x400004e0; sbrk = 0x400004e8; -isalnum = 0x400004ec; -isalpha = 0x400004f0; isascii = 0x400004f4; isblank = 0x400004f8; iscntrl = 0x400004fc; -isdigit = 0x40000500; -islower = 0x40000504; isgraph = 0x40000508; isprint = 0x4000050c; ispunct = 0x40000510; -isspace = 0x40000514; -isupper = 0x40000518; -toupper = 0x4000051c; -tolower = 0x40000520; toascii = 0x40000524; memccpy = 0x40000528; memchr = 0x4000052c; memrchr = 0x40000530; -strcasecmp = 0x40000534; strcasestr = 0x40000538; strcat = 0x4000053c; strchr = 0x40000544; strcspn = 0x40000548; -strcoll = 0x4000054c; strlcat = 0x40000550; strlcpy = 0x40000554; -strlwr = 0x40000558; -strncasecmp = 0x4000055c; strncat = 0x40000560; strnlen = 0x40000568; strrchr = 0x4000056c; strsep = 0x40000570; strspn = 0x40000574; strtok_r = 0x40000578; -strupr = 0x4000057c; longjmp = 0x40000580; setjmp = 0x40000584; abs = 0x40000588; diff --git a/components/esp_rom/esp32c61/ld/esp32c61.rom.newlib.ld b/components/esp_rom/esp32c61/ld/esp32c61.rom.newlib.ld index 0e6df59a285..80a4717173f 100644 --- a/components/esp_rom/esp32c61/ld/esp32c61.rom.newlib.ld +++ b/components/esp_rom/esp32c61/ld/esp32c61.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,3 +39,16 @@ __swhatbuf_r = 0x400005d4; __swbuf_r = 0x400005d8; __swbuf = 0x400005dc; __swsetup_r = 0x400005e0; +toupper = 0x4000051c; +tolower = 0x40000520; +isalnum = 0x400004ec; +isalpha = 0x400004f0; +isdigit = 0x40000500; +islower = 0x40000504; +isspace = 0x40000514; +isupper = 0x40000518; +strcasecmp = 0x40000534; +strcoll = 0x4000054c; +strlwr = 0x40000558; +strncasecmp = 0x4000055c; +strupr = 0x4000057c; diff --git a/components/esp_rom/esp32h2/ld/esp32h2.rom.libc.ld b/components/esp_rom/esp32h2/ld/esp32h2.rom.libc.ld index d6680a5d7fb..2ad368242c7 100644 --- a/components/esp_rom/esp32h2/ld/esp32h2.rom.libc.ld +++ b/components/esp_rom/esp32h2/ld/esp32h2.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x400004c0; strstr = 0x400004c4; bzero = 0x400004c8; sbrk = 0x400004d0; -isalnum = 0x400004d4; -isalpha = 0x400004d8; isascii = 0x400004dc; isblank = 0x400004e0; iscntrl = 0x400004e4; -isdigit = 0x400004e8; -islower = 0x400004ec; isgraph = 0x400004f0; isprint = 0x400004f4; ispunct = 0x400004f8; -isspace = 0x400004fc; -isupper = 0x40000500; -toupper = 0x40000504; -tolower = 0x40000508; toascii = 0x4000050c; memccpy = 0x40000510; memchr = 0x40000514; memrchr = 0x40000518; -strcasecmp = 0x4000051c; strcasestr = 0x40000520; strcat = 0x40000524; strchr = 0x4000052c; strcspn = 0x40000530; -strcoll = 0x40000534; strlcat = 0x40000538; strlcpy = 0x4000053c; -strlwr = 0x40000540; -strncasecmp = 0x40000544; strncat = 0x40000548; strnlen = 0x40000550; strrchr = 0x40000554; strsep = 0x40000558; strspn = 0x4000055c; strtok_r = 0x40000560; -strupr = 0x40000564; longjmp = 0x40000568; setjmp = 0x4000056c; abs = 0x40000570; diff --git a/components/esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld b/components/esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld index 770211f2c32..23922598364 100644 --- a/components/esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld +++ b/components/esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,3 +39,16 @@ __swhatbuf_r = 0x400005bc; __swbuf_r = 0x400005c0; __swbuf = 0x400005c4; __swsetup_r = 0x400005c8; +toupper = 0x40000504; +tolower = 0x40000508; +isalnum = 0x400004d4; +isalpha = 0x400004d8; +isdigit = 0x400004e8; +islower = 0x400004ec; +isspace = 0x400004fc; +isupper = 0x40000500; +strcasecmp = 0x4000051c; +strcoll = 0x40000534; +strlwr = 0x40000540; +strncasecmp = 0x40000544; +strupr = 0x40000564; diff --git a/components/esp_rom/esp32h21/ld/esp32h21.rom.libc.ld b/components/esp_rom/esp32h21/ld/esp32h21.rom.libc.ld index 18a91402e15..830b2e454aa 100644 --- a/components/esp_rom/esp32h21/ld/esp32h21.rom.libc.ld +++ b/components/esp_rom/esp32h21/ld/esp32h21.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x400004b8; strstr = 0x400004bc; bzero = 0x400004c0; sbrk = 0x400004c8; -isalnum = 0x400004cc; -isalpha = 0x400004d0; isascii = 0x400004d4; isblank = 0x400004d8; iscntrl = 0x400004dc; -isdigit = 0x400004e0; -islower = 0x400004e4; isgraph = 0x400004e8; isprint = 0x400004ec; ispunct = 0x400004f0; -isspace = 0x400004f4; -isupper = 0x400004f8; -toupper = 0x400004fc; -tolower = 0x40000500; toascii = 0x40000504; memccpy = 0x40000508; memchr = 0x4000050c; memrchr = 0x40000510; -strcasecmp = 0x40000514; strcasestr = 0x40000518; strcat = 0x4000051c; strchr = 0x40000524; strcspn = 0x40000528; -strcoll = 0x4000052c; strlcat = 0x40000530; strlcpy = 0x40000534; -strlwr = 0x40000538; -strncasecmp = 0x4000053c; strncat = 0x40000540; strnlen = 0x40000548; strrchr = 0x4000054c; strsep = 0x40000550; strspn = 0x40000554; strtok_r = 0x40000558; -strupr = 0x4000055c; longjmp = 0x40000560; setjmp = 0x40000564; abs = 0x40000568; diff --git a/components/esp_rom/esp32h21/ld/esp32h21.rom.newlib.ld b/components/esp_rom/esp32h21/ld/esp32h21.rom.newlib.ld index 1f79078a485..0d1ca973292 100644 --- a/components/esp_rom/esp32h21/ld/esp32h21.rom.newlib.ld +++ b/components/esp_rom/esp32h21/ld/esp32h21.rom.newlib.ld @@ -39,3 +39,16 @@ __swhatbuf_r = 0x400005b4; __swbuf_r = 0x400005b8; __swbuf = 0x400005bc; __swsetup_r = 0x400005c0; +toupper = 0x400004fc; +tolower = 0x40000500; +isalnum = 0x400004cc; +isalpha = 0x400004d0; +isdigit = 0x400004e0; +islower = 0x400004e4; +isspace = 0x400004f4; +isupper = 0x400004f8; +strcasecmp = 0x40000514; +strcoll = 0x4000052c; +strlwr = 0x40000538; +strncasecmp = 0x4000053c; +strupr = 0x4000055c; diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.libc.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.libc.ld index 65d90e205fe..f38b60c22f8 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.libc.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.libc.ld @@ -9,41 +9,28 @@ strlen = 0x4fc00288; strstr = 0x4fc0028c; bzero = 0x4fc00290; sbrk = 0x4fc00298; -isalnum = 0x4fc0029c; -isalpha = 0x4fc002a0; isascii = 0x4fc002a4; isblank = 0x4fc002a8; iscntrl = 0x4fc002ac; -isdigit = 0x4fc002b0; -islower = 0x4fc002b4; isgraph = 0x4fc002b8; isprint = 0x4fc002bc; ispunct = 0x4fc002c0; -isspace = 0x4fc002c4; -isupper = 0x4fc002c8; -toupper = 0x4fc002cc; -tolower = 0x4fc002d0; toascii = 0x4fc002d4; memccpy = 0x4fc002d8; memchr = 0x4fc002dc; memrchr = 0x4fc002e0; -strcasecmp = 0x4fc002e4; strcasestr = 0x4fc002e8; strcat = 0x4fc002ec; strchr = 0x4fc002f4; strcspn = 0x4fc002f8; -strcoll = 0x4fc002fc; strlcat = 0x4fc00300; strlcpy = 0x4fc00304; -strlwr = 0x4fc00308; -strncasecmp = 0x4fc0030c; strncat = 0x4fc00310; strnlen = 0x4fc00318; strrchr = 0x4fc0031c; strsep = 0x4fc00320; strspn = 0x4fc00324; strtok_r = 0x4fc00328; -strupr = 0x4fc0032c; longjmp = 0x4fc00330; setjmp = 0x4fc00334; abs = 0x4fc00338; diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld index 2929b424ff0..369d1c01fee 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld @@ -39,3 +39,16 @@ __swhatbuf_r = 0x4fc00384; __swbuf_r = 0x4fc00388; __swbuf = 0x4fc0038c; __swsetup_r = 0x4fc00390; +toupper = 0x4fc002cc; +tolower = 0x4fc002d0; +isalnum = 0x4fc0029c; +isalpha = 0x4fc002a0; +isdigit = 0x4fc002b0; +islower = 0x4fc002b4; +isspace = 0x4fc002c4; +isupper = 0x4fc002c8; +strcasecmp = 0x4fc002e4; +strcoll = 0x4fc002fc; +strlwr = 0x4fc00308; +strncasecmp = 0x4fc0030c; +strupr = 0x4fc0032c; diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.libc-funcs.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.libc-funcs.ld index ae5bc633bfc..863508a4f0d 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.libc-funcs.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.libc-funcs.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,18 +17,12 @@ PROVIDE ( __assert = 0x4001a430 ); PROVIDE ( __assert_func = 0x4001a408 ); bzero = 0x400078c8; div = 0x40000620; -isalnum = 0x400078d8; -isalpha = 0x400078e8; isascii = 0x4001aaec; isblank = 0x400078f8; iscntrl = 0x40007918; -isdigit = 0x40007930; isgraph = 0x40007968; -islower = 0x40007948; isprint = 0x40007980; ispunct = 0x40007994; -isspace = 0x400079ac; -isupper = 0x400079c4; labs = 0x40000648; ldiv = 0x40000650; longjmp = 0x400005a4; @@ -44,14 +38,11 @@ setjmp = 0x40000540; strcat = 0x4001ad90; strchr = 0x4001adb0; strcmp = 0x40007be4; -strcoll = 0x40007ce8; strcpy = 0x40007cfc; strcspn = 0x4001adcc; strlcat = 0x40007db8; strlcpy = 0x4001adf8; strlen = 0x40007e08; -strlwr = 0x40007e68; -strncasecmp = 0x40007e94; strncat = 0x4001ae34; strncmp = 0x4001ae64; strncpy = 0x40007f20; @@ -62,7 +53,4 @@ strspn = 0x4001aebc; strstr = 0x4001aee8; __strtok_r = 0x4001af18; strtok_r = 0x4001af7c; -strupr = 0x40008084; toascii = 0x4001af90; -tolower = 0x40008158; -toupper = 0x40008174; diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld index 4b8aa9c26c5..dc4ef563ab6 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -50,3 +50,15 @@ __locale_ctype_ptr_l = 0x40001c24; __locale_mb_cur_max = 0x40001c0c; strcasecmp = 0x40007b38; strcasestr = 0x40007b7c; +tolower = 0x40008158; +toupper = 0x40008174; +isalnum = 0x400078d8; +isalpha = 0x400078e8; +isdigit = 0x40007930; +islower = 0x40007948; +isspace = 0x400079ac; +isupper = 0x400079c4; +strcoll = 0x40007ce8; +strlwr = 0x40007e68; +strncasecmp = 0x40007e94; +strupr = 0x40008084; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.libc.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.libc.ld index cf3f350174d..73a3ac5e83e 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.libc.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.libc.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,41 +16,28 @@ strlen = 0x40001248; strstr = 0x40001254; bzero = 0x40001260; sbrk = 0x40001278; -isalnum = 0x40001284; -isalpha = 0x40001290; isascii = 0x4000129c; isblank = 0x400012a8; iscntrl = 0x400012b4; -isdigit = 0x400012c0; -islower = 0x400012cc; isgraph = 0x400012d8; isprint = 0x400012e4; ispunct = 0x400012f0; -isspace = 0x400012fc; -isupper = 0x40001308; -toupper = 0x40001314; -tolower = 0x40001320; toascii = 0x4000132c; memccpy = 0x40001338; memchr = 0x40001344; memrchr = 0x40001350; -strcasecmp = 0x4000135c; strcasestr = 0x40001368; strcat = 0x40001374; strchr = 0x4000138c; strcspn = 0x40001398; -strcoll = 0x400013a4; strlcat = 0x400013b0; strlcpy = 0x400013bc; -strlwr = 0x400013c8; -strncasecmp = 0x400013d4; strncat = 0x400013e0; strnlen = 0x400013f8; strrchr = 0x40001404; strsep = 0x40001410; strspn = 0x4000141c; strtok_r = 0x40001428; -strupr = 0x40001434; longjmp = 0x40001440; setjmp = 0x4000144c; abs = 0x40001458; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld index b0957aac2a5..f964e305f8a 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,3 +29,16 @@ PROVIDE( _fwalk = 0x40001518 ); PROVIDE( _fwalk_reent = 0x40001524 ); PROVIDE( __swbuf_r = 0x40001548 ); __swbuf = 0x40001554; +toupper = 0x40001314; +tolower = 0x40001320; +isalnum = 0x40001284; +isalpha = 0x40001290; +isdigit = 0x400012c0; +islower = 0x400012cc; +isspace = 0x400012fc; +isupper = 0x40001308; +strcasecmp = 0x4000135c; +strcoll = 0x400013a4; +strlwr = 0x400013c8; +strncasecmp = 0x400013d4; +strupr = 0x40001434; diff --git a/components/esp_system/ld/elf_misc.ld.in b/components/esp_system/ld/elf_misc.ld.in index d9891a34e84..ce56428853c 100644 --- a/components/esp_system/ld/elf_misc.ld.in +++ b/components/esp_system/ld/elf_misc.ld.in @@ -66,7 +66,9 @@ * And so forth... */ *(.rela.*) +#if CONFIG_LIBC_NEWLIB *(.got .got.plt) /* TODO: GCC-382 */ +#endif #if !EH_FRAME_LINKING_ENABLED *(.eh_frame_hdr) *(.eh_frame) diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index 930e1b4cdaf..fd13d6afd88 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -384,12 +384,24 @@ SECTIONS /* TLS data. */ ALIGNED_SYMBOL(4, _thread_local_start) +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata) *(.tdata.*) *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); } > default_rodata_seg + ASSERT_PICOLIBC_REENT_STUB() _flash_rodata_align = ALIGNOF(.flash.rodata); diff --git a/components/esp_system/ld/esp32c2/sections.ld.in b/components/esp_system/ld/esp32c2/sections.ld.in index 8986e499406..4db9c8e5fc8 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -188,6 +188,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -262,24 +265,41 @@ SECTIONS .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)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata .tdata.* .gnu.linkonce.td.*) - . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -292,7 +312,7 @@ SECTIONS * driver to maintain the virtual address. * NOLOAD rodata may not be included in this section. */ - _rodata_reserved_end = ADDR(.flash.tbss); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index 5c84d3cd5ad..2bd4bcfa1e5 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/sections.ld.in @@ -310,6 +310,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -384,24 +387,41 @@ SECTIONS .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)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata .tdata.* .gnu.linkonce.td.*) - . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -414,7 +434,7 @@ SECTIONS * driver to maintain the virtual address. * NOLOAD rodata may not be included in this section. */ - _rodata_reserved_end = ADDR(.flash.tbss); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c5/sections.ld.in b/components/esp_system/ld/esp32c5/sections.ld.in index 7bb97c4d928..b865acd4e0d 100644 --- a/components/esp_system/ld/esp32c5/sections.ld.in +++ b/components/esp_system/ld/esp32c5/sections.ld.in @@ -359,6 +359,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -433,32 +436,41 @@ SECTIONS .flash.tdata : { - _thread_local_data_start = ABSOLUTE(.); - - *(.tdata .tdata.* .gnu.linkonce.td.*) - - . = ALIGN(ALIGNOF(.flash.tbss)); - -#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - /* Align the end of flash rodata region as per PMP granularity to allow using the - * page alignment gap created while mapping the flash region into the PSRAM memory. + /* 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. */ - . = ALIGN(_esp_pmp_align_size); -#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC + *(.tdata .tdata.* .gnu.linkonce.td.*) + . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -466,12 +478,18 @@ SECTIONS */ .flash.rodata_noload (NOLOAD) : { +#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION + /* Align the end of flash rodata region as per PMP granularity to allow using the + * page alignment gap created while mapping the flash region into the PSRAM memory. + */ + . = ALIGN(_esp_pmp_align_size); +#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION /** * 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); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index f2b2df7926e..ed1841e2a79 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -355,6 +355,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -429,24 +432,41 @@ SECTIONS .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)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata .tdata.* .gnu.linkonce.td.*) - . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -459,7 +479,7 @@ SECTIONS * driver to maintain the virtual address. * NOLOAD rodata may not be included in this section. */ - _rodata_reserved_end = ADDR(.flash.tbss); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c61/sections.ld.in b/components/esp_system/ld/esp32c61/sections.ld.in index e6c48b54528..40b7d82740c 100644 --- a/components/esp_system/ld/esp32c61/sections.ld.in +++ b/components/esp_system/ld/esp32c61/sections.ld.in @@ -204,6 +204,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -278,32 +281,41 @@ SECTIONS .flash.tdata : { - _thread_local_data_start = ABSOLUTE(.); - - *(.tdata .tdata.* .gnu.linkonce.td.*) - - . = ALIGN(ALIGNOF(.flash.tbss)); - -#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - /* Align the end of flash rodata region as per PMP granularity to allow using the - * page alignment gap created while mapping the flash region into the PSRAM memory. + /* 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. */ - . = ALIGN(_esp_pmp_align_size); -#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC + *(.tdata .tdata.* .gnu.linkonce.td.*) + . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -311,12 +323,18 @@ SECTIONS */ .flash.rodata_noload (NOLOAD) : { +#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION + /* Align the end of flash rodata region as per PMP granularity to allow using the + * page alignment gap created while mapping the flash region into the PSRAM memory. + */ + . = ALIGN(_esp_pmp_align_size); +#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION /** * 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); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32h2/sections.ld.in b/components/esp_system/ld/esp32h2/sections.ld.in index be973ed63c1..09dd47ed2e4 100644 --- a/components/esp_system/ld/esp32h2/sections.ld.in +++ b/components/esp_system/ld/esp32h2/sections.ld.in @@ -357,6 +357,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -431,24 +434,41 @@ SECTIONS .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)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata .tdata.* .gnu.linkonce.td.*) - . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -461,7 +481,7 @@ SECTIONS * driver to maintain the virtual address. * NOLOAD rodata may not be included in this section. */ - _rodata_reserved_end = ADDR(.flash.tbss); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32h21/sections.ld.in b/components/esp_system/ld/esp32h21/sections.ld.in index dc628feefff..cb7b93517c7 100644 --- a/components/esp_system/ld/esp32h21/sections.ld.in +++ b/components/esp_system/ld/esp32h21/sections.ld.in @@ -346,6 +346,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -420,24 +423,41 @@ SECTIONS .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)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata .tdata.* .gnu.linkonce.td.*) - . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -450,7 +470,7 @@ SECTIONS * driver to maintain the virtual address. * NOLOAD rodata may not be included in this section. */ - _rodata_reserved_end = ADDR(.flash.tbss); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32h4/sections.ld.in b/components/esp_system/ld/esp32h4/sections.ld.in index 9e5761b2c1f..3dbf9aa964e 100644 --- a/components/esp_system/ld/esp32h4/sections.ld.in +++ b/components/esp_system/ld/esp32h4/sections.ld.in @@ -191,6 +191,9 @@ SECTIONS mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -265,24 +268,41 @@ SECTIONS .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)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata .tdata.* .gnu.linkonce.td.*) - . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > default_rodata_seg ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + 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 @@ -295,7 +315,7 @@ SECTIONS * driver to maintain the virtual address. * NOLOAD rodata may not be included in this section. */ - _rodata_reserved_end = ADDR(.flash.tbss); + _rodata_reserved_end = .; mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in index b062587f7cc..d3a97e81241 100644 --- a/components/esp_system/ld/esp32p4/sections.ld.in +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -362,6 +362,9 @@ SECTIONS arrays[flash_rodata] mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -442,32 +445,41 @@ SECTIONS .flash.tdata : { - _thread_local_data_start = ABSOLUTE(.); - - *(.tdata .tdata.* .gnu.linkonce.td.*) - - . = ALIGN(ALIGNOF(.flash.tbss)); - -#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - /* Align the end of flash rodata region as per PMP granularity to allow using the - * page alignment gap created while mapping the flash region into the PSRAM memory. + /* 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. */ - . = ALIGN(_esp_pmp_align_size); -#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC + *(.tdata .tdata.* .gnu.linkonce.td.*) + . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > rodata_seg_low ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > rodata_seg_low + 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 @@ -475,12 +487,18 @@ SECTIONS */ .flash.rodata_noload (NOLOAD) : { +#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION + /* Align the end of flash rodata region as per PMP granularity to allow using the + * page alignment gap created while mapping the flash region into the PSRAM memory. + */ + . = ALIGN(_esp_pmp_align_size); +#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION /** * 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); + _rodata_reserved_end = .; arrays[rodata_noload] mapping[rodata_noload] diff --git a/components/esp_system/ld/esp32p4/sections.rev3.ld.in b/components/esp_system/ld/esp32p4/sections.rev3.ld.in index d8cbd257294..3ff1254a5b3 100644 --- a/components/esp_system/ld/esp32p4/sections.rev3.ld.in +++ b/components/esp_system/ld/esp32p4/sections.rev3.ld.in @@ -388,6 +388,9 @@ SECTIONS arrays[flash_rodata] mapping[flash_rodata] +#if CONFIG_LIBC_PICOLIBC + *(.got .got.plt) /* TODO: GCC-439 */ +#endif *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -405,6 +408,7 @@ SECTIONS * Excluding crtbegin.o/crtend.o since IDF doesn't use the toolchain crt. */ ALIGNED_SYMBOL(4, __preinit_array_start) + ALIGNED_SYMBOL(4, __bothinit_array_start) KEEP (*(.preinit_array)) __preinit_array_end = ABSOLUTE(.); @@ -417,6 +421,7 @@ SECTIONS ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) __init_array_end = ABSOLUTE(.); + __bothinit_array_end = ABSOLUTE(.); /* Addresses of memory regions reserved via SOC_RESERVE_MEMORY_REGION() */ ALIGNED_SYMBOL(4, soc_reserved_memory_region_start) @@ -466,32 +471,41 @@ SECTIONS .flash.tdata : { - _thread_local_data_start = ABSOLUTE(.); - - *(.tdata .tdata.* .gnu.linkonce.td.*) - - . = ALIGN(ALIGNOF(.flash.tbss)); - -#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - /* Align the end of flash rodata region as per PMP granularity to allow using the - * page alignment gap created while mapping the flash region into the PSRAM memory. + /* 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. */ - . = ALIGN(_esp_pmp_align_size); -#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - + /* tdata sections */ + _thread_local_data_start = ABSOLUTE(.); +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC + *(.tdata .tdata.* .gnu.linkonce.td.*) + . = ALIGN(ALIGNOF(.flash.tbss)); _thread_local_data_end = ABSOLUTE(.); } > rodata_seg_low ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) + ASSERT_PICOLIBC_REENT_STUB() .flash.tbss (NOLOAD) : { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); } > rodata_seg_low + 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 @@ -499,12 +513,18 @@ SECTIONS */ .flash.rodata_noload (NOLOAD) : { +#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION + /* Align the end of flash rodata region as per PMP granularity to allow using the + * page alignment gap created while mapping the flash region into the PSRAM memory. + */ + . = ALIGN(_esp_pmp_align_size); +#endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION /** * 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); + _rodata_reserved_end = .; arrays[rodata_noload] mapping[rodata_noload] diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index f0df70ac032..f73da102338 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -387,12 +387,24 @@ SECTIONS /* TLS data. */ ALIGNED_SYMBOL(4, _thread_local_start) +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata) *(.tdata.*) *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); } > default_rodata_seg + ASSERT_PICOLIBC_REENT_STUB() _flash_rodata_align = ALIGNOF(.flash.rodata); diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index f2939764285..bf71a95412a 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -399,12 +399,24 @@ SECTIONS /* TLS data. */ ALIGNED_SYMBOL(4, _thread_local_start) +#if CONFIG_LIBC_PICOLIBC + _picolibc_reent_stub_start = ABSOLUTE(.); + KEEP(*(.tdata.errno)) +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + /* Reproduce the public fields from struct _reent. */ + KEEP(*(.tdata.tls_stdin)) + KEEP(*(.tdata.tls_stdout)) + KEEP(*(.tdata.tls_stderr)) +#endif // CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + _picolibc_reent_stub_end = ABSOLUTE(.); +#endif // CONFIG_LIBC_PICOLIBC *(.tdata) *(.tdata.*) *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); } > default_rodata_seg + ASSERT_PICOLIBC_REENT_STUB() _flash_rodata_align = ALIGNOF(.flash.rodata); diff --git a/components/esp_system/ld/ld.common b/components/esp_system/ld/ld.common index 2af596f33ee..f2e2570ef75 100644 --- a/components/esp_system/ld/ld.common +++ b/components/esp_system/ld/ld.common @@ -109,3 +109,14 @@ ASSERT((ADDR(NEXT_SECTION) == ADDR(PREV_SECTION) + SIZEOF(PREV_SECTION)), \ #else #define SECTION_AFTER_FLASH_RODATA .flash.tdata #endif + +#if CONFIG_LIBC_PICOLIBC +# if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +# define PICOLIBC_REENT_STUB 16 +# else +# define PICOLIBC_REENT_STUB 4 +# endif +#define ASSERT_PICOLIBC_REENT_STUB() ASSERT((_picolibc_reent_stub_end - _picolibc_reent_stub_start) == PICOLIBC_REENT_STUB, "Newlib _reent stub have wrong size") +#else +#define ASSERT_PICOLIBC_REENT_STUB() +#endif diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index f77b172e31d..63f0c8659e6 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -194,6 +194,21 @@ static void core_intr_matrix_clear(void) #endif // SOC_INT_CLIC_SUPPORTED } +#if CONFIG_LIBC_PICOLIBC +FORCE_INLINE_ATTR IRAM_ATTR void init_pre_rtos_tls_area(int cpu_num) +{ + /** + * Initialize the TLS area before RTOS starts, in case any code tries to access + * TLS variables. + * + * TODO IDF-14914: Currently, we only initialize errno, which is the first TLS + * variable as guaranteed by the linker script. + */ + static int s_errno_array[SOC_CPU_CORES_NUM]; + esp_cpu_set_threadptr(&s_errno_array[cpu_num]); +} +#endif + #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE void startup_resume_other_cores(void) { @@ -214,6 +229,10 @@ void ESP_SYSTEM_IRAM_ATTR call_start_cpu1(void) ); #endif //#ifdef __riscv +#if CONFIG_LIBC_PICOLIBC + init_pre_rtos_tls_area(1); +#endif + #if SOC_BRANCH_PREDICTOR_SUPPORTED esp_cpu_branch_prediction_enable(); #endif //#if SOC_BRANCH_PREDICTOR_SUPPORTED @@ -935,6 +954,10 @@ void IRAM_ATTR call_start_cpu0(void) // Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. init_bss(rst_reas); +#if CONFIG_LIBC_PICOLIBC + init_pre_rtos_tls_area(0); +#endif + // When the APP is loaded into ram for execution, some hardware initialization steps used to be executed in the // bootloader are done here. #if CONFIG_APP_BUILD_TYPE_RAM diff --git a/components/hal/platform_port/include/hal/assert.h b/components/hal/platform_port/include/hal/assert.h index 48e5c3ba65e..c8db9b4c872 100644 --- a/components/hal/platform_port/include/hal/assert.h +++ b/components/hal/platform_port/include/hal/assert.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,8 +11,20 @@ extern "C" { #endif -extern void __assert_func(const char *file, int line, const char *func, const char *expr); -extern void abort(void); +#if CONFIG_LIBC_PICOLIBC +#if defined(__cplusplus) && __cplusplus >= 201103L +#define __noreturn [[noreturn]] +#elif __has_attribute(__noreturn__) +#define __noreturn __attribute__((__noreturn__)) +#else +#define __noreturn +#endif +#else +#define __noreturn +#endif + +__noreturn void __assert_func(const char *file, int line, const char *func, const char *expr); +__noreturn void abort(void); #ifndef __ASSERT_FUNC #ifdef __ASSERT_FUNCTION diff --git a/components/heap/test_apps/heap_tests/main/test_heap_trace.c b/components/heap/test_apps/heap_tests/main/test_heap_trace.c index f50b7e02a03..9df51df2888 100644 --- a/components/heap/test_apps/heap_tests/main/test_heap_trace.c +++ b/components/heap/test_apps/heap_tests/main/test_heap_trace.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -128,13 +128,21 @@ TEST_CASE("heap trace wrapped buffer check", "[heap-trace]") heap_trace_stop(); } -static void print_floats_task(void *ignore) +static void trace_libc_allocs_task(void *ignore) { heap_trace_start(HEAP_TRACE_ALL); + +#if CONFIG_LIBC_NEWLIB char buf[16] = { }; volatile float f = 12.3456; sprintf(buf, "%.4f", f); TEST_ASSERT_EQUAL_STRING("12.3456", buf); +#endif +#if CONFIG_LIBC_PICOLIBC + FILE* f = fdopen(100, "r"); + fclose(f); +#endif + heap_trace_stop(); vTaskDelete(NULL); @@ -158,11 +166,10 @@ TEST_CASE("can trace allocations made by newlib", "[heap-trace]") - We also do the tracing in the task so we only capture things directly related to it. */ - xTaskCreate(print_floats_task, "print_float", 4096, NULL, 5, NULL); + xTaskCreate(trace_libc_allocs_task, "trace_libc_allocs_task", 4096, NULL, 5, NULL); vTaskDelay(10); - /* has to be at least a few as newlib allocates via multiple different function calls */ - TEST_ASSERT(heap_trace_get_count() > 3); + TEST_ASSERT(heap_trace_get_count() > 0); } TEST_CASE("can stop recording allocs but continue recording frees", "[heap-trace]") diff --git a/components/lwip/port/esp32xx/include/arch/cc.h b/components/lwip/port/esp32xx/include/arch/cc.h index 486e2782bdc..656a82ae0f4 100644 --- a/components/lwip/port/esp32xx/include/arch/cc.h +++ b/components/lwip/port/esp32xx/include/arch/cc.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-3-Clause * - * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD */ #ifndef __ARCH_CC_H__ #define __ARCH_CC_H__ @@ -25,10 +25,18 @@ extern "C" { #endif // BYTE_ORDER #define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#ifndef htons #define htons(x) __builtin_bswap16(x) +#endif +#ifndef ntohs #define ntohs(x) __builtin_bswap16(x) +#endif +#ifndef htonl #define htonl(x) __builtin_bswap32(x) +#endif +#ifndef ntohl #define ntohl(x) __builtin_bswap32(x) +#endif #ifndef CONFIG_LWIP_ESP_LWIP_ASSERT #define LWIP_NOASSERT 1 diff --git a/components/lwip/test_apps/main/lwip_test.c b/components/lwip/test_apps/main/lwip_test.c index 187f5abd918..4611648e9c7 100644 --- a/components/lwip/test_apps/main/lwip_test.c +++ b/components/lwip/test_apps/main/lwip_test.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include "freertos/FreeRTOS.h" diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index d7c0a0bf882..29363db53ef 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -63,7 +63,11 @@ else() list(APPEND srcs "src/picolibc/picolibc_init.c" "src/picolibc/rand.c" - "src/picolibc/open_memstream.c") + "src/picolibc/open_memstream.c" + "src/picolibc/errno.c") + if(CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY) + list(APPEND srcs "src/picolibc/getreent.c") + endif() endif() list(APPEND ldfragments "src/newlib.lf" "src/system_libs.lf") diff --git a/components/newlib/Kconfig b/components/newlib/Kconfig index 9a30784c218..17e9d383581 100644 --- a/components/newlib/Kconfig +++ b/components/newlib/Kconfig @@ -7,10 +7,40 @@ menu "LibC" config LIBC_NEWLIB bool "NewLib" config LIBC_PICOLIBC - bool "Picolibc (EXPERIMENTAL)" - depends on !IDF_TOOLCHAIN_CLANG && IDF_EXPERIMENTAL_FEATURES + bool "Picolibc" + depends on !IDF_TOOLCHAIN_CLANG endchoice + config LIBC_PICOLIBC_NEWLIB_COMPATIBILITY + bool "Provides limited interoperability with libraries built using Newlib headers" + default y + depends on LIBC_PICOLIBC + help + This option provides limited compatibility with libraries built using Newlib headers by: + + Enabling hidden system-header inclusions that exist in Newlib. + Adding tls_stdio, tls_stdout, and tls_stderr variables to Thread Local Storage + to allow prebuilt libraries to access them via getreent(). + Providing an implementation of getreent() that returns the value of the thread-pointer register. + + Limitations: + + 1. If your application or an external prebuilt library accesses Newlib "struct _reent" implicitly, + this may cause memory corruption on the task stack. You have two options: + + - Use libc API calls instead of directly accessing "struct _reent" fields. + - Switch ESP-IDF to use the Newlib implementation by setting CONFIG_LIBC_NEWLIB=y in sdkconfig. + + 2. If your application uses a prebuilt library built with Newlib headers, you may encounter + unexpected behavior when overriding stdin, stdout, and stderr. External prebuilt libraries + can only read these streams, so overriding them will not affect as it was for Newlib. + You have two options to fix this: + + - Rebuild the library with Picolibc headers that follow POSIX-standardized stdin, stdout, + and stderr declarations. + - Switch ESP-IDF to use the Newlib implementation by setting CONFIG_LIBC_NEWLIB=y in sdkconfig. + + config LIBC_MISC_IN_IRAM bool "Place misc libc functions (abort/assert/stdatomics) in IRAM" if SPI_FLASH_AUTO_SUSPEND default y @@ -18,7 +48,6 @@ menu "LibC" config LIBC_LOCKS_PLACE_IN_IRAM bool "Place lock API in IRAM" default y - depends on LIBC_NEWLIB help Enable this option to include be able to call the lock API from code that runs while cache is disabled, e.g. IRAM interrupts. diff --git a/components/newlib/platform_include/stdio.h b/components/newlib/platform_include/stdio.h index 282bc2319cc..2322f9a8dd0 100644 --- a/components/newlib/platform_include/stdio.h +++ b/components/newlib/platform_include/stdio.h @@ -1,16 +1,24 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#include_next #include "sdkconfig.h" -#include_next +#ifdef __cplusplus +extern "C" { +#endif -#if CONFIG_LIBC_PICOLIBC +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#include void flockfile(FILE *); void funlockfile(FILE *); FILE *open_memstream(char **, size_t *); #endif + +#ifdef __cplusplus +} +#endif diff --git a/components/newlib/platform_include/stdio_ext.h b/components/newlib/platform_include/stdio_ext.h index 8c49947ff3e..0ac12ebe123 100644 --- a/components/newlib/platform_include/stdio_ext.h +++ b/components/newlib/platform_include/stdio_ext.h @@ -9,6 +9,8 @@ #if CONFIG_LIBC_NEWLIB #include_next -#else +#endif + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY #include #endif diff --git a/components/newlib/platform_include/sys/cdefs.h b/components/newlib/platform_include/sys/cdefs.h new file mode 100644 index 00000000000..d87dbd85aa0 --- /dev/null +++ b/components/newlib/platform_include/sys/cdefs.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include_next +#include "sdkconfig.h" + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#include +#include +#endif diff --git a/components/newlib/platform_include/sys/fcntl.h b/components/newlib/platform_include/sys/fcntl.h new file mode 100644 index 00000000000..93c9cb458c8 --- /dev/null +++ b/components/newlib/platform_include/sys/fcntl.h @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" + +#include_next + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#include +#include +#endif diff --git a/components/newlib/platform_include/sys/time.h b/components/newlib/platform_include/sys/time.h index 7901acca33e..88ca7867aa8 100644 --- a/components/newlib/platform_include/sys/time.h +++ b/components/newlib/platform_include/sys/time.h @@ -1,9 +1,13 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once + +#include "sdkconfig.h" + +#if CONFIG_LIBC_NEWLIB /* Newlib sys/time.h defines timerisset, timerclear, timercmp, timeradd, timersub macros for __CYGWIN__ and __rtems__. We want to define these macros in IDF as well. Since we wish to use un-modified newlib headers until a patched newlib version is @@ -20,3 +24,10 @@ #define __rtems__ #include_next #undef __rtems__ +#else // CONFIG_LIBC_NEWLIB +#include_next +#endif // CONFIG_LIBC_NEWLIB + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#include +#endif diff --git a/components/newlib/platform_include/sys/unistd.h b/components/newlib/platform_include/sys/unistd.h index 483fd3cca82..d6b152f7b17 100644 --- a/components/newlib/platform_include/sys/unistd.h +++ b/components/newlib/platform_include/sys/unistd.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,11 @@ #pragma once #include +#include "sdkconfig.h" + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#include +#endif #include_next diff --git a/components/newlib/project_include.cmake b/components/newlib/project_include.cmake index e3651702835..193f166f2c2 100644 --- a/components/newlib/project_include.cmake +++ b/components/newlib/project_include.cmake @@ -16,6 +16,8 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) else() idf_toolchain_remove_flags(LINK_OPTIONS "--specs=nano.specs") endif() + + idf_toolchain_rerun_abi_detection() else() # TODO IDF-14338 if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND) diff --git a/components/newlib/sbom.yml b/components/newlib/sbom.yml index 496cb10c30b..6c88c6fa0c5 100644 --- a/components/newlib/sbom.yml +++ b/components/newlib/sbom.yml @@ -1,9 +1,7 @@ -name: 'newlib' -version: '4.3.0' -cpe: cpe:2.3:a:newlib_project:newlib:{}:*:*:*:*:*:*:* +name: 'esp_libc' supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' -originator: 'Organization: Red Hat Incorporated' +originator: 'Organization: Espressif Systems (Shanghai) CO LTD' description: An open-source C standard library implementation with additional features and patches from Espressif. -cve-exclude-list: - - cve: CVE-2024-30949 - reason: A vulnerability was discovered in the gettimeofday system call implementation within the RISC-V libgloss component of Newlib. ESP-IDF does not link against libgloss for RISC-V, hence the issue is not directly applicable. Still, the relevant fix has been patched through https://github.com/espressif/newlib-esp32/commit/047ba47013c2656a1e7838dc86cbc75aeeaa67a7 +virtpackages: + - sbom_newlibc.yml + - sbom_picolibc.yml== diff --git a/components/newlib/sbom_newlibc.yml b/components/newlib/sbom_newlibc.yml new file mode 100644 index 00000000000..1a4e9db9897 --- /dev/null +++ b/components/newlib/sbom_newlibc.yml @@ -0,0 +1,10 @@ +if: 'LIBC_NEWLIB' +name: 'newlib' +version: '4.3.0' +cpe: cpe:2.3:a:newlib_project:newlib:{}:*:*:*:*:*:*:* +supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' +originator: 'Organization: Red Hat Incorporated' +description: Newlib is a small C standard library for embedded systems +cve-exclude-list: + - cve: CVE-2024-30949 + reason: A vulnerability was discovered in the gettimeofday system call implementation within the RISC-V libgloss component of Newlib. ESP-IDF does not link against libgloss for RISC-V, hence the issue is not directly applicable. Still, the relevant fix has been patched through https://github.com/espressif/newlib-esp32/commit/047ba47013c2656a1e7838dc86cbc75aeeaa67a7 diff --git a/components/newlib/sbom_picolibc.yml b/components/newlib/sbom_picolibc.yml new file mode 100644 index 00000000000..4056cc42217 --- /dev/null +++ b/components/newlib/sbom_picolibc.yml @@ -0,0 +1,6 @@ +if: 'LIBC_PICOLIBC' +name: 'picolib' +version: '1.8.10' +supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' +originator: 'Organization: keithp.com/picolibc' +description: C Libraries for Smaller Embedded Systems diff --git a/components/newlib/src/locks.c b/components/newlib/src/locks.c index 582256dc3d5..580f7b0e7ec 100644 --- a/components/newlib/src/locks.c +++ b/components/newlib/src/locks.c @@ -17,9 +17,9 @@ #include "sdkconfig.h" #if CONFIG_LIBC_LOCKS_PLACE_IN_IRAM -#define NEWLIB_LOCKS_IRAM_ATTR IRAM_ATTR +#define LIBC_LOCKS_IRAM_ATTR IRAM_ATTR #else -#define NEWLIB_LOCKS_IRAM_ATTR +#define LIBC_LOCKS_IRAM_ATTR #endif /* Notes on our newlib lock implementation: @@ -50,7 +50,7 @@ static portMUX_TYPE lock_init_spinlock = portMUX_INITIALIZER_UNLOCKED; Called by _lock_init*, also called by _lock_acquire* to lazily initialize locks that might have been initialised (to zero only) before the RTOS scheduler started. */ -static void NEWLIB_LOCKS_IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type) +static void LIBC_LOCKS_IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mutex_type) { portENTER_CRITICAL(&lock_init_spinlock); if (*lock) { @@ -81,13 +81,13 @@ static void NEWLIB_LOCKS_IRAM_ATTR lock_init_generic(_lock_t *lock, uint8_t mute portEXIT_CRITICAL(&lock_init_spinlock); } -void NEWLIB_LOCKS_IRAM_ATTR _lock_init(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_init(_lock_t *lock) { *lock = 0; // In case lock's memory is uninitialized lock_init_generic(lock, queueQUEUE_TYPE_MUTEX); } -void NEWLIB_LOCKS_IRAM_ATTR _lock_init_recursive(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_init_recursive(_lock_t *lock) { *lock = 0; // In case lock's memory is uninitialized lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX); @@ -103,7 +103,7 @@ void NEWLIB_LOCKS_IRAM_ATTR _lock_init_recursive(_lock_t *lock) re-initialised if it is used again. Caller has to avoid doing this! */ -void NEWLIB_LOCKS_IRAM_ATTR _lock_close(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_close(_lock_t *lock) { portENTER_CRITICAL(&lock_init_spinlock); if (*lock) { @@ -122,7 +122,7 @@ void _lock_close_recursive(_lock_t *lock) __attribute__((alias("_lock_close"))); /* Acquire the mutex semaphore for lock. wait up to delay ticks. mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX */ -static int NEWLIB_LOCKS_IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type) +static int LIBC_LOCKS_IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t delay, uint8_t mutex_type) { SemaphoreHandle_t h = (SemaphoreHandle_t)(*lock); if (!h) { @@ -164,22 +164,22 @@ static int NEWLIB_LOCKS_IRAM_ATTR lock_acquire_generic(_lock_t *lock, uint32_t d return (success == pdTRUE) ? 0 : -1; } -void NEWLIB_LOCKS_IRAM_ATTR _lock_acquire(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_acquire(_lock_t *lock) { lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_MUTEX); } -void NEWLIB_LOCKS_IRAM_ATTR _lock_acquire_recursive(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_acquire_recursive(_lock_t *lock) { lock_acquire_generic(lock, portMAX_DELAY, queueQUEUE_TYPE_RECURSIVE_MUTEX); } -int NEWLIB_LOCKS_IRAM_ATTR _lock_try_acquire(_lock_t *lock) +int LIBC_LOCKS_IRAM_ATTR _lock_try_acquire(_lock_t *lock) { return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_MUTEX); } -int NEWLIB_LOCKS_IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock) +int LIBC_LOCKS_IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock) { return lock_acquire_generic(lock, 0, queueQUEUE_TYPE_RECURSIVE_MUTEX); } @@ -187,7 +187,7 @@ int NEWLIB_LOCKS_IRAM_ATTR _lock_try_acquire_recursive(_lock_t *lock) /* Release the mutex semaphore for lock. mutex_type is queueQUEUE_TYPE_RECURSIVE_MUTEX or queueQUEUE_TYPE_MUTEX */ -static void NEWLIB_LOCKS_IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type) +static void LIBC_LOCKS_IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t mutex_type) { if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { return; /* locking is a no-op before scheduler is up */ @@ -213,12 +213,12 @@ static void NEWLIB_LOCKS_IRAM_ATTR lock_release_generic(_lock_t *lock, uint8_t m } } -void NEWLIB_LOCKS_IRAM_ATTR _lock_release(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_release(_lock_t *lock) { lock_release_generic(lock, queueQUEUE_TYPE_MUTEX); } -void NEWLIB_LOCKS_IRAM_ATTR _lock_release_recursive(_lock_t *lock) +void LIBC_LOCKS_IRAM_ATTR _lock_release_recursive(_lock_t *lock) { lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX); } @@ -291,69 +291,69 @@ static StaticSemaphore_t s_common_recursive_mutex; #define MAYBE_OVERRIDE_LOCK(_lock, _lock_to_use_instead) #endif // ROM_NEEDS_MUTEX_OVERRIDE -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_init(_LOCK_T *lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_init(_LOCK_T *lock) { *lock = NULL; /* In case lock's memory is uninitialized */ lock_init_generic(lock, queueQUEUE_TYPE_MUTEX); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_init_recursive(_LOCK_T *lock) { *lock = NULL; /* In case lock's memory is uninitialized */ lock_init_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_close(_LOCK_T lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_close(_LOCK_T lock) { _lock_close(&lock); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_close_recursive(_LOCK_T lock) { _lock_close_recursive(&lock); } /* Separate function, to prevent generating multiple assert strings */ -static void NEWLIB_LOCKS_IRAM_ATTR check_lock_nonzero(_LOCK_T lock) +static void LIBC_LOCKS_IRAM_ATTR check_lock_nonzero(_LOCK_T lock) { assert(lock != NULL && "Uninitialized lock used"); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_acquire(_LOCK_T lock) { check_lock_nonzero(lock); MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex); _lock_acquire(&lock); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_acquire_recursive(_LOCK_T lock) { check_lock_nonzero(lock); MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex); _lock_acquire_recursive(&lock); } -int NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock) +int LIBC_LOCKS_IRAM_ATTR __retarget_lock_try_acquire(_LOCK_T lock) { check_lock_nonzero(lock); MAYBE_OVERRIDE_LOCK(lock, &s_common_mutex); return _lock_try_acquire(&lock); } -int NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock) +int LIBC_LOCKS_IRAM_ATTR __retarget_lock_try_acquire_recursive(_LOCK_T lock) { check_lock_nonzero(lock); MAYBE_OVERRIDE_LOCK(lock, &s_common_recursive_mutex); return _lock_try_acquire_recursive(&lock); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_release(_LOCK_T lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_release(_LOCK_T lock) { check_lock_nonzero(lock); _lock_release(&lock); } -void NEWLIB_LOCKS_IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock) +void LIBC_LOCKS_IRAM_ATTR __retarget_lock_release_recursive(_LOCK_T lock) { check_lock_nonzero(lock); _lock_release_recursive(&lock); diff --git a/components/newlib/src/picolibc/errno.c b/components/newlib/src/picolibc/errno.c new file mode 100644 index 00000000000..67479c0ed7f --- /dev/null +++ b/components/newlib/src/picolibc/errno.c @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/* + * Picolibc does not initialize 'errno' and places it in the TBSS section. + * + * To allow convenient initialization and support interoperability with Newlib, + * 'errno' is defined in the TDATA section. The linker script ensures that + * it is positioned at the beginning of the TDATA segment. + */ +__thread int errno __attribute__((section(".tdata.errno"))) = 0; + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +int *__errno(void) +{ + return &errno; +} +#endif diff --git a/components/newlib/src/picolibc/getreent.c b/components/newlib/src/picolibc/getreent.c new file mode 100644 index 00000000000..b494d52ee50 --- /dev/null +++ b/components/newlib/src/picolibc/getreent.c @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "esp_cpu.h" + +void *__getreent(void) +{ + /* + * The linker script provides the basic _reent fields + * used to access errno and stdin/stdout/stderr. + * + * Note: if code accesses other fields in struct _reent + * that are not intended to be "public," data corruption may occur. + */ + return esp_cpu_get_threadptr(); +} diff --git a/components/newlib/src/picolibc/picolibc_init.c b/components/newlib/src/picolibc/picolibc_init.c index 2e0fc30f148..7bd52667cbe 100644 --- a/components/newlib/src/picolibc/picolibc_init.c +++ b/components/newlib/src/picolibc/picolibc_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,17 +33,8 @@ static void esp_cleanup_r(struct _reent *rptr) #endif #if ESP_ROM_HAS_RETARGETABLE_LOCKING -static int __retarget_lock_try_acquire(struct __lock * p) -{ - __retarget_lock_acquire(p); - return 0; -} - -static int __retarget_lock_try_acquire_recursive(struct __lock *p) -{ - __retarget_lock_acquire_recursive(p); - return 0; -} +int __retarget_lock_try_acquire(struct __lock * p); +int __retarget_lock_try_acquire_recursive(struct __lock *p); #endif static struct syscall_stub_table s_stub_table = { @@ -143,20 +134,10 @@ void esp_reent_cleanup(void) return; } -#if CONFIG_VFS_SUPPORT_IO -FILE *stdin; -FILE *stdout; -FILE *stderr; -void esp_libc_init_global_stdio(const char *stdio_dev) -{ - stdin = fopen(stdio_dev, "r"); - stdout = fopen(stdio_dev, "w"); - assert(stdin); - assert(stdout); - setlinebuf(stdout); - stderr = stdout; -} -#else /* CONFIG_VFS_SUPPORT_IO */ +/* + * Initialize stdin, stdout, and stderr using static memory allocation. + * Creating them with fopen() would call malloc() internally. + */ static char write_buf[BUFSIZ]; static char read_buf[BUFSIZ]; @@ -166,10 +147,28 @@ static struct __file_bufio __stdout = FDEV_SETUP_BUFIO(1, write_buf, BUFSIZ, rea FILE *stdin = &__stdin.xfile.cfile.file; FILE *stdout = &__stdout.xfile.cfile.file; FILE *stderr = &__stdout.xfile.cfile.file; + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +__thread FILE* tls_stdin = &__stdin.xfile.cfile.file; +__thread FILE* tls_stdout = &__stdout.xfile.cfile.file; +__thread FILE* tls_stderr = &__stdout.xfile.cfile.file; +#endif + +#if CONFIG_VFS_SUPPORT_IO +void esp_libc_init_global_stdio(const char *stdio_dev) +{ + int stdin_fd = open(stdio_dev, O_RDONLY); + assert(stdin_fd > 0); + __stdin.ptr = (void *)(intptr_t)(stdin_fd); + + int stdout_fd = open(stdio_dev, O_WRONLY); + assert(stdout_fd > 0); + __stdout.ptr = (void *)(intptr_t)(stdout_fd); +} +#else /* CONFIG_VFS_SUPPORT_IO */ void esp_libc_init_global_stdio(void) { - __lock_init_recursive(stdin->lock); - __lock_init_recursive(stdout->lock); + /* Nothing to do. */ } #endif /* CONFIG_VFS_SUPPORT_IO */ diff --git a/components/newlib/src/syscalls.c b/components/newlib/src/syscalls.c index 0a15125fc34..d9dbe9e85af 100644 --- a/components/newlib/src/syscalls.c +++ b/components/newlib/src/syscalls.c @@ -105,6 +105,10 @@ int fcntl(int fd, int cmd, ...) return _fcntl_r(__getreent(), fd, cmd, arg); } +int getpid() +{ + return _getpid_r(__getreent()); +} #endif // CONFIG_LIBC_PICOLIBC void _exit(int __status) diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index af3dff5fc21..7cbc43e99eb 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -131,6 +131,18 @@ FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_set_cycle_count(u #endif } +FORCE_INLINE_ATTR void rv_utils_set_threadptr(void *ptr) +{ + asm volatile("mv tp, %0" :: "r"(ptr)); +} + +FORCE_INLINE_ATTR void *rv_utils_get_threadptr(void) +{ + void *thread_ptr; + asm volatile("mv %0, tp" : "=r"(thread_ptr)); + return thread_ptr; +} + /* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ diff --git a/components/sdmmc/include/sd_protocol_defs.h b/components/sdmmc/include/sd_protocol_defs.h index f943789dc80..ba0c32f8c5e 100644 --- a/components/sdmmc/include/sd_protocol_defs.h +++ b/components/sdmmc/include/sd_protocol_defs.h @@ -25,6 +25,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/components/soc/esp32p4/register/hw_ver3/soc/pmu_struct.h b/components/soc/esp32p4/register/hw_ver3/soc/pmu_struct.h index 676f27357a6..abc5f66321b 100644 --- a/components/soc/esp32p4/register/hw_ver3/soc/pmu_struct.h +++ b/components/soc/esp32p4/register/hw_ver3/soc/pmu_struct.h @@ -7,6 +7,7 @@ #include #include +#include #include "pmu_reg.h" #ifdef __cplusplus extern "C" { diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake index bbc288c2817..ad2c6b6bc41 100644 --- a/components/soc/project_include.cmake +++ b/components/soc/project_include.cmake @@ -36,14 +36,15 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) # Clean compile options that were added by previous configurations and may be outdated idf_toolchain_remove_flags(COMPILE_OPTIONS "-march=") - if(CONFIG_SOC_CPU_HAS_HWLOOP) - set(_march "${_march}_xesploop") - endif() + if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + set(_march "${_march}_xesppie") + else() + if(CONFIG_SOC_CPU_HAS_HWLOOP) + set(_march "${_march}_xesploop") + endif() - if(CONFIG_SOC_CPU_HAS_PIE) - set(_march "${_march}_xespv") - if(CONFIG_ESP32P4_SELECTS_REV_LESS_V3) - set(_march "${_march}2p1") + if(CONFIG_SOC_CPU_HAS_PIE) + set(_march "${_march}_xespv") endif() endif() @@ -60,30 +61,8 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) if(NOT CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE) idf_toolchain_add_flags(COMPILE_OPTIONS "-mtune=esp-base") endif() + idf_toolchain_rerun_abi_detection() else() message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}") endif() - - # Workaround: Re-run CMake compiler ABI detection after ABI flags are set. - # - # Problem: CMake performs compiler checks at an early stage during - # toolchain.cmake processing. At this early stage, response files are not yet - # ready, which causes CMake paths (e.g., CMAKE__IMPLICIT_LINK_DIRECTORIES) - # to be incorrectly determined. - # - # Solution: Re-run the ABI detection after ABI flags are present to correctly - # determine these paths. - # - # Note: If the CMake API changes, this solution may need to be revised. - set(lang_ext_pairs "C|c" "CXX|cpp") - include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) - foreach(lang_ext ${lang_ext_pairs}) - string(REPLACE "|" ";" lang_ext_parts ${lang_ext}) - list(GET lang_ext_parts 0 lang) - list(GET lang_ext_parts 1 ext) - if(DEFINED CMAKE_${lang}_ABI_COMPILED) - unset(CMAKE_${lang}_ABI_COMPILED) - cmake_determine_compiler_abi(${lang} ${CMAKE_ROOT}/Modules/CMake${lang}CompilerABI.${ext}) - endif() - endforeach() endif() diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index c8399d5cfe0..a4cfc2b37da 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "esp_tls.h" #include "esp_log.h" diff --git a/components/ulp/esp32ulp_mapgen.py b/components/ulp/esp32ulp_mapgen.py index 972d8fd3e22..f841c436e9f 100755 --- a/components/ulp/esp32ulp_mapgen.py +++ b/components/ulp/esp32ulp_mapgen.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 # # esp32ulp_mapgen utility converts a symbol list provided by nm into an export script @@ -16,50 +16,61 @@ UTIL = os.path.basename(__file__) def name_mangling(name: str) -> str: # Simple and dumb name mangling for namespaced name following GCC algorithm ns, n = name.split('::') - return '_ZN{0}{1}{2}{3}E'.format(len(ns), ns, len(n), n) + return f'_ZN{len(ns)}{ns}{len(n)}{n}E' -def gen_ld_h_from_sym(f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.TextIO, base_addr: int, prefix: str) -> None: - f_ld.write(textwrap.dedent( - f""" +def gen_ld_h_from_sym( + f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.TextIO, base_addr: int, prefix: str +) -> None: + f_ld.write( + textwrap.dedent( + f""" /* ULP variable definitions for the linker. * This file is generated automatically by {UTIL} utility. */ """ # noqa: E222 - )) + ) + ) cpp_mode = False var_prefix = prefix namespace = '' if '::' in prefix: # C++ mode, let's avoid the extern "C" type and instead use namespace - f_h.write(textwrap.dedent( - f""" + f_h.write( + textwrap.dedent( + f""" /* ULP variable definitions for the compiler. * This file is generated automatically by {UTIL} utility. */ #pragma once """ # noqa: E222 - )) + ) + ) tmp = prefix.split('::') namespace = tmp[0] var_prefix = '_'.join(tmp[1:]) # Limit to a single namespace here to avoid complex mangling rules f_h.write(f'namespace {namespace} {{\n') cpp_mode = True else: - f_h.write(textwrap.dedent( - f""" + f_h.write( + textwrap.dedent( + f""" /* ULP variable definitions for the compiler. * This file is generated automatically by {UTIL} utility. */ #pragma once + #include #ifdef __cplusplus extern "C" {{ #endif\n """ # noqa: E222 - )) + ) + ) # Format the regular expression to match the readelf output - expr = re.compile(r'^.*(?P
[a-f0-9]{8})\s+(?P\d+) (OBJECT|NOTYPE)\s+GLOBAL\s+DEFAULT\s+[^ ]+ (?P.*)$') + expr = re.compile( + r'^.*(?P
[a-f0-9]{8})\s+(?P\d+) (OBJECT|NOTYPE)\s+GLOBAL\s+DEFAULT\s+[^ ]+ (?P.*)$' + ) for line in f_sym: # readelf format output has the following structure: # Num: Value Size Type Bind Vis Ndx Name @@ -90,23 +101,31 @@ def gen_ld_h_from_sym(f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.Tex if cpp_mode: f_h.write('}\n') else: - f_h.write(textwrap.dedent( - """ + f_h.write( + textwrap.dedent( + """ #ifdef __cplusplus } #endif """ - )) + ) + ) def main() -> None: - description = ('This application generates .h and .ld files for symbols defined in input file. ' - 'The input symbols file can be generated using readelf utility like this: ' - 'readelf -sW > ') + description = ( + 'This application generates .h and .ld files for symbols defined in input file. ' + 'The input symbols file can be generated using readelf utility like this: ' + 'readelf -sW > ' + ) parser = argparse.ArgumentParser(description=description) - parser.add_argument('-s', '--symfile', required=True, help='symbols file name', metavar='SYMFILE', type=argparse.FileType('r')) - parser.add_argument('-o', '--outputfile', required=True, help='destination .h and .ld files name prefix', metavar='OUTFILE') + parser.add_argument( + '-s', '--symfile', required=True, help='symbols file name', metavar='SYMFILE', type=argparse.FileType('r') + ) + parser.add_argument( + '-o', '--outputfile', required=True, help='destination .h and .ld files name prefix', metavar='OUTFILE' + ) parser.add_argument('--base-addr', required=True, help='base address of the ULP memory, to be added to each symbol') parser.add_argument('-p', '--prefix', required=False, help='prefix for generated header file', default='ulp_') diff --git a/components/vfs/test_apps/main/test_vfs_fd.c b/components/vfs/test_apps/main/test_vfs_fd.c index 94814539cd9..353701cdca1 100644 --- a/components/vfs/test_apps/main/test_vfs_fd.c +++ b/components/vfs/test_apps/main/test_vfs_fd.c @@ -7,6 +7,7 @@ #include "sdkconfig.h" #include #include +#include #include #include #include diff --git a/components/vfs/test_apps/main/test_vfs_lwip.c b/components/vfs/test_apps/main/test_vfs_lwip.c index e9cf3870ab5..d496648d83b 100644 --- a/components/vfs/test_apps/main/test_vfs_lwip.c +++ b/components/vfs/test_apps/main/test_vfs_lwip.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "unity.h" #include "test_utils.h" diff --git a/components/vfs/test_apps/main/test_vfs_select.c b/components/vfs/test_apps/main/test_vfs_select.c index 80f7720cca1..538c5e38170 100644 --- a/components/vfs/test_apps/main/test_vfs_select.c +++ b/components/vfs/test_apps/main/test_vfs_select.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "unity.h" #include "freertos/FreeRTOS.h" #include "driver/uart.h" diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index bcd5efa3d54..1a0518f3cfb 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" diff --git a/components/xtensa/include/xt_utils.h b/components/xtensa/include/xt_utils.h index d4678002d91..afe5cb135bb 100644 --- a/components/xtensa/include/xt_utils.h +++ b/components/xtensa/include/xt_utils.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -82,6 +82,18 @@ FORCE_INLINE_ATTR void xt_utils_wait_for_intr(void) asm volatile ("waiti 0\n"); } +FORCE_INLINE_ATTR void xt_utils_set_threadptr(void *ptr) +{ + asm volatile ("wur.threadptr %0" :: "r"(ptr)); +} + +FORCE_INLINE_ATTR void *xt_utils_get_threadptr(void) +{ + void *thread_ptr; + asm volatile ("rur.threadptr %0" : "=r"(thread_ptr)); + return thread_ptr; +} + /* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ diff --git a/docs/en/api-guides/stdio.rst b/docs/en/api-guides/stdio.rst index f0b10cfaed3..ccb1598dc9d 100644 --- a/docs/en/api-guides/stdio.rst +++ b/docs/en/api-guides/stdio.rst @@ -58,13 +58,26 @@ Enabling one of these option will cause the corresponding VFS driver to be built Standard Streams and FreeRTOS Tasks ----------------------------------- +ESP-IDF provides two different implementations of standard I/O streams based on the selected LibC implementation defined by :ref:`CONFIG_LIBC`. The behavior of ``stdin``, ``stdout``, and ``stderr`` streams differs between these implementations, particularly regarding how they are shared across FreeRTOS tasks. + +Common to both implementations, each stream (``stdin``, ``stdout``, ``stderr``) has a mutex associated with it to protect the stream from concurrent access by multiple tasks. For example, if two tasks are writing to ``stdout`` at the same time, the mutex ensures that the outputs from each task are not mixed together. + +Newlib +^^^^^^ + In ESP-IDF, to save RAM, ``FILE`` objects for ``stdin``, ``stdout``, and ``stderr`` are shared between all FreeRTOS tasks, but the pointers to these objects are unique for every task. This means that: - It is possible to change ``stdin``, ``stdout``, and ``stderr`` for any given task without affecting other tasks, e.g., by doing ``stdin = fopen("/dev/uart/1", "r")``. - To change the default ``stdin``, ``stdout``, ``stderr`` streams for new tasks, modify ``_GLOBAL_REENT->_stdin`` (``_stdout``, ``_stderr``) before creating the task. - Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` closes the ``FILE`` stream object, which will affect all other tasks. -Each stream (``stdin``, ``stdout``, ``stderr``) has a mutex associated with it. This mutex is used to protect the stream from concurrent access by multiple tasks. For example, if two tasks are writing to ``stdout`` at the same time, the mutex will ensure that the outputs from each task are not mixed together. +Picolibc +^^^^^^^^ + +According to the POSIX standard, all default ``stdin``, ``stdout``, and ``stderr`` streams are global and shared between all FreeRTOS tasks. This means that: + +- Modifying ``stdin``, ``stdout``, or ``stderr`` will affect all other tasks. It is not possible to change standard I/O streams for specific tasks. +- If a thread-local stream is needed, it should be implemented in the application code by opening a file stream and using it within tasks, e.g., ``fscanf()``, ``fprintf()``, etc. Blocking and non-blocking I/O ----------------------------- diff --git a/examples/network/simple_sniffer/main/cmd_sniffer.c b/examples/network/simple_sniffer/main/cmd_sniffer.c index aae307df62b..64367a750c6 100644 --- a/examples/network/simple_sniffer/main/cmd_sniffer.c +++ b/examples/network/simple_sniffer/main/cmd_sniffer.c @@ -7,6 +7,7 @@ */ #include #include +#include #include "argtable3/argtable3.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c index fbcd3f1658c..f0673c19499 100644 --- a/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c +++ b/examples/openthread/ot_sleepy_device/deep_sleep/main/esp_ot_sleepy_device.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "esp_err.h" #include "esp_event.h" #include "esp_log.h" diff --git a/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c b/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c index abc01a900a8..4e872f5e215 100644 --- a/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c +++ b/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "esp_vfs.h" #include "esp_vfs_fat.h" #include "esp_err.h" diff --git a/tools/cmake/toolchain_flags.cmake b/tools/cmake/toolchain_flags.cmake index 682e4e2602b..cd273040fdb 100644 --- a/tools/cmake/toolchain_flags.cmake +++ b/tools/cmake/toolchain_flags.cmake @@ -155,3 +155,28 @@ endfunction() function(idf_toolchain_remove_flags) _process_toolchain_flag_options() endfunction() + +# Workaround: Re-run CMake compiler ABI detection after ABI flags are set. +# +# Problem: CMake performs compiler checks at an early stage during +# toolchain.cmake processing. At this early stage, response files are not yet +# ready, which causes CMake paths (e.g., CMAKE__IMPLICIT_LINK_DIRECTORIES) +# to be incorrectly determined. +# +# Solution: Re-run the ABI detection after ABI flags are present to correctly +# determine these paths. +# +# Note: If the CMake API changes, this solution may need to be revised. +macro(idf_toolchain_rerun_abi_detection) + set(lang_ext_pairs "C|c" "CXX|cpp") + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + foreach(lang_ext ${lang_ext_pairs}) + string(REPLACE "|" ";" lang_ext_parts ${lang_ext}) + list(GET lang_ext_parts 0 lang) + list(GET lang_ext_parts 1 ext) + if(DEFINED CMAKE_${lang}_ABI_COMPILED) + unset(CMAKE_${lang}_ABI_COMPILED) + cmake_determine_compiler_abi(${lang} ${CMAKE_ROOT}/Modules/CMake${lang}CompilerABI.${ext}) + endif() + endforeach() +endmacro() diff --git a/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c b/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c index dbbc75263eb..2372c22f308 100644 --- a/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c +++ b/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "esp_vfs.h" #include "esp_vfs_fat.h" #include "sdkconfig.h" From 09f8bf33996294d3d791dfd65d1d28a2cb6157d7 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Fri, 14 Nov 2025 02:00:48 +0700 Subject: [PATCH 04/18] fix(esp_phy): use toolchain flags for external project --- components/esp_phy/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_phy/CMakeLists.txt b/components/esp_phy/CMakeLists.txt index 24defd87b17..b56525c7f1f 100644 --- a/components/esp_phy/CMakeLists.txt +++ b/components/esp_phy/CMakeLists.txt @@ -120,7 +120,7 @@ if(CONFIG_ESP_PHY_ENABLED) add_custom_command( OUTPUT ${phy_init_data_bin} DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/phy_init_data.c - COMMAND ${CMAKE_C_COMPILER} -c ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/phy_init_data.c + COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/phy_init_data.c -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include -I ${esp_rom_dir}/include -I ${soc_dir}/${idf_target}/include -I ${newlib_dir}/platform_include From c4826656387f6fdd9fdcebf13dad92887222a659 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 26 Nov 2025 16:12:52 +0700 Subject: [PATCH 05/18] fix(ci): fix check_public_headers.py to check system headers --- .gitlab/ci/host-test.yml | 38 ++++++++++++------ tools/ci/check_public_headers.py | 66 ++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 29 deletions(-) diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index eded76d04b5..833d5a0a04e 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -23,18 +23,32 @@ check_public_headers: - .host_test_template - .rules:build:check script: - - IDF_TARGET=esp32 python tools/ci/check_public_headers.py --jobs 4 --prefix xtensa-esp32-elf- - - IDF_TARGET=esp32s2 python tools/ci/check_public_headers.py --jobs 4 --prefix xtensa-esp32s2-elf- - - IDF_TARGET=esp32s3 python tools/ci/check_public_headers.py --jobs 4 --prefix xtensa-esp32s3-elf- - - IDF_TARGET=esp32c3 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32c2 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32c6 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32c5 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32h2 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32p4 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32c61 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32h21 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- - - IDF_TARGET=esp32h4 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf- + - | + targets="esp32 \ + esp32s2 \ + esp32s3 \ + esp32c3 \ + esp32c2 \ + esp32c6 \ + esp32c5 \ + esp32h2 \ + esp32p4 \ + esp32c61 \ + esp32h21 \ + esp32h4" + for libc in newlib picolibc; do + for target in ${targets}; do + case "${target}" in + esp32|esp32s2|esp32s3) + PREFIX="xtensa-${target}-elf-" + ;; + *) + PREFIX="riscv32-esp-elf-" + ;; + esac + IDF_TARGET=${target} python tools/ci/check_public_headers.py --jobs 4 --prefix ${PREFIX} --libc-type ${libc} + done + done test_nvs_coverage: extends: diff --git a/tools/ci/check_public_headers.py b/tools/ci/check_public_headers.py index 72b4fefdb99..a8c3891c8c6 100644 --- a/tools/ci/check_public_headers.py +++ b/tools/ci/check_public_headers.py @@ -11,6 +11,7 @@ import json import os import queue import re +import shutil import subprocess import tempfile from threading import Event @@ -87,9 +88,9 @@ class PublicHeaderChecker: if self.verbose or debug: print(message) - def __init__(self, verbose: bool = False, jobs: int = 1, prefix: Optional[str] = None) -> None: - self.gcc = '{}gcc'.format(prefix) - self.gpp = '{}g++'.format(prefix) + def __init__(self, libc_type: str, verbose: bool = False, jobs: int = 1, prefix: Optional[str] = None) -> None: + self.gcc = f'{prefix}gcc' + self.gpp = f'{prefix}g++' self.verbose = verbose self.jobs = jobs self.prefix = prefix @@ -106,10 +107,12 @@ class PublicHeaderChecker: self.check_threads: List[Thread] = [] self.stdc = '--std=c99' self.stdcpp = '--std=c++17' + self.libc_type = libc_type self.job_queue: queue.Queue = queue.Queue() self.failed_queue: queue.Queue = queue.Queue() self.terminate = Event() + self.build_dir = tempfile.mkdtemp() def __enter__(self) -> 'PublicHeaderChecker': for i in range(self.jobs): @@ -122,6 +125,7 @@ class PublicHeaderChecker: self.terminate.set() for t in self.check_threads: t.join() + shutil.rmtree(self.build_dir) # thread function process incoming header file from a queue def check_headers(self, num: int) -> None: @@ -154,14 +158,33 @@ class PublicHeaderChecker: # - Compile the header with both C and C++ compiler def check_one_header(self, header: str, num: int) -> None: self.preprocess_one_header(header, num) - self.compile_one_header_with(self.gcc, self.stdc, header) - self.compile_one_header_with(self.gpp, self.stdcpp, header) + temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.c', dir=self.build_dir, delete=False) + compile_file = temp_file.name + with temp_file: + # There can not `-include {header}` be used because in this case system headers + # which are overridden in ESP-IDF have wrong include_next behavior. + # This happens because file was already included but search paths are: + # - components/esp_libc/platform_include + # - toolchain_system_include_path + # So, when checking headers from platform_include directory, + # they will not include system headers by include_next. + # To fix this, header is included to the source file. + if 'platform_include' in header: + sys_header = header.split('platform_include/')[1] + temp_file.write(f'#include <{sys_header}>\n') + else: + temp_file.write(f'#include "{header}"\n') + temp_file.write(f'#include "{self.main_c}"\n') + self.compile_one_header_with(self.gcc, self.stdc, header, compile_file) + self.compile_one_header_with(self.gpp, self.stdcpp, header, compile_file) # Checks if the header contains some assembly code and whether it is compilable - def compile_one_header_with(self, compiler: str, std_flags: str, header: str) -> None: - rc, out, err, cmd = exec_cmd( - [compiler, std_flags, '-S', '-o-', '-include', header, self.main_c] + self.include_dir_flags - ) + def compile_one_header_with(self, compiler: str, std_flags: str, header: str, compile_file: str) -> None: + cmd_list = [compiler, std_flags, '-S', '-o-', compile_file] + self.include_dir_flags + if self.libc_type == 'picolibc': + cmd_list.append('-specs=picolibc.specs') + + rc, out, err, cmd = exec_cmd(cmd_list) if rc == 0: if not re.sub(self.assembly_nocode, '', out, flags=re.M).isspace(): raise HeaderFailedContainsCode() @@ -200,6 +223,9 @@ class PublicHeaderChecker: header, self.main_c, ] + self.include_dir_flags + if self.libc_type == 'picolibc': + all_compilation_flags.append('-specs=picolibc.specs') + # just strip comments to check for CONFIG_... macros or static asserts rc, out, err, _ = exec_cmd([self.gcc, '-fpreprocessed', '-dD', '-P', '-E', header] + self.include_dir_flags) # we ignore the rc here, as the `-fpreprocessed` flag expects the file to have macros already expanded, @@ -284,14 +310,17 @@ class PublicHeaderChecker: if idf_path is None: raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.") project_dir = os.path.join(idf_path, 'examples', 'get-started', 'blink') - build_dir = tempfile.mkdtemp() - sdkconfig = os.path.join(build_dir, 'sdkconfig') + sdkconfig = os.path.join(self.build_dir, 'sdkconfig') + if self.libc_type == 'picolibc': + with open(sdkconfig, 'w') as f: + f.write('CONFIG_LIBC_PICOLIBC=y\n') try: os.unlink(os.path.join(project_dir, 'sdkconfig')) except FileNotFoundError: pass subprocess.check_call( - ['idf.py', '-B', build_dir, f'-DSDKCONFIG={sdkconfig}', '-DCOMPONENTS=', 'reconfigure'], cwd=project_dir + ['idf.py', '-B', self.build_dir, f'-DSDKCONFIG={sdkconfig}', '-DCOMPONENTS=', 'reconfigure'], + cwd=project_dir, ) def get_std(json: List, extension: str) -> str: @@ -299,7 +328,7 @@ class PublicHeaderChecker: command = [c for c in j if c['file'].endswith('.' + extension) and '-std=' in c['command']][0] return str([s for s in command['command'].split() if 'std=' in s][0]) # grab the std flag - build_commands_json = os.path.join(build_dir, 'compile_commands.json') + build_commands_json = os.path.join(self.build_dir, 'compile_commands.json') with open(build_commands_json, 'r', encoding='utf-8') as f: j = json.load(f) self.stdc = get_std(j, 'c') @@ -317,13 +346,13 @@ class PublicHeaderChecker: include_dir_flags.append( item.replace('\\', '') ) # removes escaped quotes, eg: -DMBEDTLS_CONFIG_FILE=\\\"mbedtls/esp_config.h\\\" - include_dir_flags.append('-I' + os.path.join(build_dir, 'config')) + include_dir_flags.append('-I' + os.path.join(self.build_dir, 'config')) include_dir_flags.append('-DCI_HEADER_CHECK') - sdkconfig_h = os.path.join(build_dir, 'config', 'sdkconfig.h') + sdkconfig_h = os.path.join(self.build_dir, 'config', 'sdkconfig.h') # prepares a main_c file for easier sdkconfig checks and avoid compilers warning when compiling headers directly with open(sdkconfig_h, 'a') as f: f.write('#define IDF_SDKCONFIG_INCLUDED') - main_c = os.path.join(build_dir, 'compile.c') + main_c = os.path.join(self.build_dir, 'compile.c') with open(main_c, 'w') as f: f.write( '#if defined(IDF_CHECK_SDKCONFIG_INCLUDED) && ! defined(IDF_SDKCONFIG_INCLUDED)\n' @@ -406,6 +435,9 @@ def check_all_headers() -> None: '--exclude-file', '-e', help='exception file', default='check_public_headers_exceptions.txt', type=str ) parser.add_argument('--only-dir', '-d', help='reduce the analysis to this directory only', default=None, type=str) + parser.add_argument( + '--libc-type', '-l', help='type of libc to use', default='picolibc', choices=['picolibc', 'newlib'], type=str + ) args = parser.parse_args() # process excluded files and dirs @@ -423,7 +455,7 @@ def check_all_headers() -> None: ignore_files.append(line) # start header check - with PublicHeaderChecker(args.verbose, args.jobs, args.prefix) as header_check: + with PublicHeaderChecker(args.libc_type, args.verbose, args.jobs, args.prefix) as header_check: header_check.list_public_headers(ignore_dirs, ignore_files, only_dir=args.only_dir) try: header_check.join() From 2909fccdfe12aafb44d8ef2bc7e0c89840712298 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 26 Nov 2025 16:14:34 +0700 Subject: [PATCH 06/18] fix(esp_coex): add missing include for sdkconfig.h --- components/esp_coex/include/private/esp_modem_wrapper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_coex/include/private/esp_modem_wrapper.h b/components/esp_coex/include/private/esp_modem_wrapper.h index 8ce7a3a433f..8ea05515328 100644 --- a/components/esp_coex/include/private/esp_modem_wrapper.h +++ b/components/esp_coex/include/private/esp_modem_wrapper.h @@ -14,6 +14,7 @@ extern "C" { #include #include #include +#include "sdkconfig.h" bool esp_coex_common_env_is_chip_wrapper(void); From 7dd7edabaa7fc6961f685bd4d6c116a19c06d2c4 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Tue, 11 Nov 2025 22:39:21 +0700 Subject: [PATCH 07/18] fix(esp_tee): build esp_tee only with CONFIG_LIBC_NEWLIB to reduce size --- components/esp_tee/CMakeLists.txt | 3 +- components/esp_tee/project_include.cmake | 20 ++++++-- components/esp_tee/subproject/CMakeLists.txt | 3 +- .../esp_tee/subproject/main/CMakeLists.txt | 4 +- .../subproject/main/common/multi_heap.c | 35 +++++++++++++ .../subproject/main/common/syscall_stubs.c | 50 +++++++++++++++++++ .../newlib/src/picolibc/picolibc_init.c | 47 +++++++++++++++++ 7 files changed, 153 insertions(+), 9 deletions(-) diff --git a/components/esp_tee/CMakeLists.txt b/components/esp_tee/CMakeLists.txt index 908067d0c21..fc58bbed717 100644 --- a/components/esp_tee/CMakeLists.txt +++ b/components/esp_tee/CMakeLists.txt @@ -104,11 +104,12 @@ if(CONFIG_SECURE_ENABLE_TEE AND NOT esp_tee_build) list(APPEND exclude_srv "attestation") endif() + idf_build_get_property(secure_service_headers_dir SECURE_SERVICE_HEADERS_DIR) execute_process( COMMAND python ${secure_service_yml_parser_py} "--sec_srv" ${secure_service_yml} "--exclude" ${exclude_srv} - WORKING_DIRECTORY ${CONFIG_DIR} + WORKING_DIRECTORY ${secure_service_headers_dir} ) execute_process( diff --git a/components/esp_tee/project_include.cmake b/components/esp_tee/project_include.cmake index b3c0e912659..cb6fd8aa301 100644 --- a/components/esp_tee/project_include.cmake +++ b/components/esp_tee/project_include.cmake @@ -6,7 +6,6 @@ idf_build_get_property(python PYTHON) idf_build_get_property(extra_cmake_args EXTRA_CMAKE_ARGS) idf_build_get_property(project_dir PROJECT_DIR) idf_build_get_property(non_os_build NON_OS_BUILD) -idf_build_get_property(config_dir CONFIG_DIR) idf_build_get_property(custom_secure_service_dir CUSTOM_SECURE_SERVICE_COMPONENT_DIR) idf_build_get_property(custom_secure_service_component CUSTOM_SECURE_SERVICE_COMPONENT) @@ -33,13 +32,24 @@ set(tee_binary_files "${TEE_BUILD_DIR}/esp_tee.map" ) +# Use only Newlib libc to reduce binary size, as some Newlib functions are already available in ROM +set(esp_tee_sdkconfig "${CMAKE_CURRENT_BINARY_DIR}/sdkconfig.esp_tee") +configure_file("${sdkconfig}" "${esp_tee_sdkconfig}" COPYONLY) +file(APPEND "${esp_tee_sdkconfig}" "\nCONFIG_LIBC_NEWLIB=y\n") + +set(secure_service_headers_dir "${CMAKE_CURRENT_BINARY_DIR}/secure_service_headers") +make_directory(${secure_service_headers_dir}) +idf_build_set_property(SECURE_SERVICE_HEADERS_DIR "${secure_service_headers_dir}") +include_directories("${secure_service_headers_dir}") + externalproject_add(esp_tee SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject" BINARY_DIR "${TEE_BUILD_DIR}" - CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} - -DCONFIG_DIR=${config_dir} -DCUSTOM_SECURE_SERVICE_COMPONENT=${custom_secure_service_component} - -DCUSTOM_SECURE_SERVICE_COMPONENT_DIR=${custom_secure_service_dir} - ${extra_cmake_args} ${sign_key_arg} + CMAKE_ARGS -DSDKCONFIG=${esp_tee_sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} + -DCUSTOM_SECURE_SERVICE_COMPONENT=${custom_secure_service_component} + -DCUSTOM_SECURE_SERVICE_COMPONENT_DIR=${custom_secure_service_dir} + -DSECURE_SERVICE_HEADERS_DIR=${secure_service_headers_dir} + ${extra_cmake_args} ${sign_key_arg} INSTALL_COMMAND "" BUILD_ALWAYS 1 # no easy way around this... USES_TERMINAL_CONFIGURE TRUE diff --git a/components/esp_tee/subproject/CMakeLists.txt b/components/esp_tee/subproject/CMakeLists.txt index b4d77bd32be..74a1094809d 100644 --- a/components/esp_tee/subproject/CMakeLists.txt +++ b/components/esp_tee/subproject/CMakeLists.txt @@ -30,8 +30,7 @@ list(APPEND COMPONENTS bootloader_support efuse esp_security mbedtls) # TEE-specific components list(APPEND COMPONENTS tee_flash_mgr tee_ota_ops tee_sec_storage tee_attestation) -# Include sdkconfig.h derived from the parent build. -include_directories(${CONFIG_DIR}) +include_directories("${SECURE_SERVICE_HEADERS_DIR}") include("${IDF_PATH}/tools/cmake/project.cmake") set(common_req esp_common esp_hw_support esp_rom freertos hal log newlib soc spi_flash) diff --git a/components/esp_tee/subproject/main/CMakeLists.txt b/components/esp_tee/subproject/main/CMakeLists.txt index 83a77c34cea..36ec492f0ab 100644 --- a/components/esp_tee/subproject/main/CMakeLists.txt +++ b/components/esp_tee/subproject/main/CMakeLists.txt @@ -61,7 +61,7 @@ idf_component_register(SRCS ${srcs} # NOTE: The ESP32-H2 ROM does not have sprintf/snprintf implementation, # thus newlib-nano implementation from the toolchain has been used. -if(CONFIG_IDF_TARGET_ESP32H2) +if(CONFIG_LIBC_NEWLIB AND CONFIG_IDF_TARGET_ESP32H2) target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs") endif() @@ -76,6 +76,8 @@ target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_app_desc_tee_include_impl # Newlib syscalls stub implementation: Linking symbol target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_tee_include_syscalls_impl") +target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_tee_include_heap_impl") + # cut PROJECT_VER and PROJECT_NAME to required 32 characters. idf_build_get_property(project_ver PROJECT_VER) idf_build_get_property(project_name PROJECT_NAME) diff --git a/components/esp_tee/subproject/main/common/multi_heap.c b/components/esp_tee/subproject/main/common/multi_heap.c index 4261bd73dd7..49d963a8e65 100644 --- a/components/esp_tee/subproject/main/common/multi_heap.c +++ b/components/esp_tee/subproject/main/common/multi_heap.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include "esp_rom_tlsf.h" @@ -151,6 +152,33 @@ void *calloc(size_t n, size_t size) return esp_tee_heap_calloc(n, size); } +#if CONFIG_LIBC_PICOLIBC +void *realloc(void* ptr, size_t size) +{ + if (tee_heap == NULL) { + return NULL; + } + + if (ptr == NULL) { + return esp_tee_heap_malloc(heap, size); + } + + size_t previous_block_size = tlsf_block_size(ptr); + void *result = tlsf_realloc(tee_heap->heap_data, ptr, size); + if (result) { + /* No need to subtract the tlsf_alloc_overhead() as it has already + * been subtracted when allocating the block at first with malloc */ + tee_heap->free_bytes += previous_block_size; + tee_heap->free_bytes -= tlsf_block_size(result); + if (tee_heap->free_bytes < tee_heap->minimum_free_bytes) { + tee_heap->minimum_free_bytes = tee_heap->free_bytes; + } + } + + return result; +} +#endif + void free(void *ptr) { esp_tee_heap_free(ptr); @@ -206,3 +234,10 @@ void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t } return ptr; } + +/* No-op function, used to force linking this file, + instead of the heap implementation from libc. + */ +void esp_tee_include_heap_impl(void) +{ +} diff --git a/components/esp_tee/subproject/main/common/syscall_stubs.c b/components/esp_tee/subproject/main/common/syscall_stubs.c index ee810a1aac2..01c337fb22d 100644 --- a/components/esp_tee/subproject/main/common/syscall_stubs.c +++ b/components/esp_tee/subproject/main/common/syscall_stubs.c @@ -15,7 +15,9 @@ #include #include "esp_random.h" +#include "sdkconfig.h" +#if CONFIG_LIBC_NEWLIB // NOTE: Remove compile-time warnings for the below newlib-provided functions struct _reent *__getreent(void) { @@ -68,6 +70,54 @@ int _getentropy_r(struct _reent *r, void *buffer, size_t length) esp_fill_random(buffer, length); return 0; } +#else +int fstat(int fd, struct stat *st) +{ + errno = ENOSYS; + return -1; +} + +int close(int fd) +{ + errno = ENOSYS; + return -1; +} + +off_t lseek(int fd, off_t offset, int whence) +{ + errno = ENOSYS; + return -1; +} + +ssize_t read(int fd, void *ptr, size_t len) +{ + errno = ENOSYS; + return -1; +} + +ssize_t write(int fd, const void *ptr, size_t len) +{ + errno = ENOSYS; + return -1; +} + +int getpid(void) +{ + return 1; +} + +int kill(int pid, int sig) +{ + errno = ENOSYS; + return -1; +} + +int getentropy(void *buffer, size_t length) +{ + esp_fill_random(buffer, length); + return 0; +} +#endif // CONFIG_LIBC_NEWLIB void *pthread_getspecific(pthread_key_t key) { diff --git a/components/newlib/src/picolibc/picolibc_init.c b/components/newlib/src/picolibc/picolibc_init.c index 7bd52667cbe..07540a4e554 100644 --- a/components/newlib/src/picolibc/picolibc_init.c +++ b/components/newlib/src/picolibc/picolibc_init.c @@ -37,8 +37,55 @@ int __retarget_lock_try_acquire(struct __lock * p); int __retarget_lock_try_acquire_recursive(struct __lock *p); #endif +#if CONFIG_SECURE_ENABLE_TEE +struct _reent_stub { + int _errno; + __FILE *_stdin, *_stdout, *_stderr; + int _inc; + char *_emergency; + int _reserved_0; + int _reserved_1; + struct __locale_t *_locale; + void *_mp; + void (*__cleanup)(struct _reent *); + int _gamma_signgam; + int _cvtlen; + char *_cvtbuf; + struct _rand48 *_r48; +#if 0 /* unlikely used fields in ROM implementation */ + struct __tm *_localtime_buf; + char *_asctime_buf; + void (** _sig_func)(int); + struct _atexit *_reserved_6; + struct _atexit _reserved_7; + struct _glue _reserved_8; + __FILE *__sf; + struct _misc_reent *_misc; + char *_signal_buf; +#endif +}; + +void *__getreent_rom_stub(void) +{ + static struct _reent_stub reent_stub; + return &reent_stub; +} +#endif // SECURE_ENABLE_TEE + static struct syscall_stub_table s_stub_table = { +#if CONFIG_SECURE_ENABLE_TEE + /* + * ESP-TEE uses snprintf() from ROM, which requires at least a fake __getreent stub. + * + * NOTE: If floating-point variables are intended to be used, + * the following fields must be specified in the syscall_stub_table: + * ._printf_float = + * ._scanf_float = + */ + .__getreent = (void *)__getreent_rom_stub, +#else .__getreent = (void *)abort, +#endif ._malloc_r = (void *)abort, ._free_r = (void *)abort, ._realloc_r = (void *)abort, From 7161408eb0f2ba02345ec878d18ae198bae6a310 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Fri, 28 Nov 2025 14:27:31 +0700 Subject: [PATCH 08/18] fix(console): add linenoise multithreading support for Picolibc --- components/console/CMakeLists.txt | 11 +++ components/console/esp_console_common.c | 29 ++++++- components/console/esp_console_repl_chip.c | 33 ++++++++ components/console/linenoise/linenoise.c | 8 ++ .../console/private_include/console_private.h | 4 + .../private_include/console_stdio_private.h | 79 +++++++++++++++++++ .../test_apps/console/main/CMakeLists.txt | 8 +- .../test_apps/console/main/test_app_main.c | 14 +++- .../test_apps/console/main/test_console.c | 33 ++++++++ 9 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 components/console/private_include/console_stdio_private.h diff --git a/components/console/CMakeLists.txt b/components/console/CMakeLists.txt index a6c7632830b..2647e14675d 100644 --- a/components/console/CMakeLists.txt +++ b/components/console/CMakeLists.txt @@ -1,5 +1,8 @@ idf_build_get_property(target IDF_TARGET) +# Note: Almost all source files in this component include console_stdio_private.h. +# This header only affects LIBC_PICOLIBC builds, not LIBC_NEWLIB builds. +# It enables thread-local stdio streams, which are required for console functionality in some cases. set(srcs "commands.c" "esp_console_common.c" "esp_console_repl_internal.c" @@ -40,6 +43,14 @@ idf_component_register(SRCS ${srcs} esp_driver_usb_serial_jtag ) +if(CONFIG_LIBC_PICOLIBC) + list(APPEND srcs_include_stdio_private ${srcs}) + list(APPEND srcs_include_stdio_private ${argtable_srcs}) + list(REMOVE_ITEM srcs_include_stdio_private "esp_console_repl_chip.c" "esp_console_repl_linux.c") + set_source_files_properties(${srcs_include_stdio_private} + PROPERTIES COMPILE_FLAGS "--include=console_stdio_private.h") +endif() + if(CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO IDF-10085 target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-analyzer") endif() diff --git a/components/console/esp_console_common.c b/components/console/esp_console_common.c index ce5c61b4a73..17c0ec62ba8 100644 --- a/components/console/esp_console_common.c +++ b/components/console/esp_console_common.c @@ -30,6 +30,19 @@ esp_err_t esp_console_setup_prompt(const char *prompt, esp_console_repl_com_t *r snprintf(repl_com->prompt, CONSOLE_PROMPT_MAX_LEN - 1, LOG_COLOR_I "%s " LOG_RESET_COLOR, prompt_temp); /* Figure out if the terminal supports escape sequences */ + /* TODO IDF-14901: It is not appropriate to probe the current thread's console here. + * The esp_console_repl_task can open its own stdin/stdout for use. + * However, linenoiseProbe() cannot be moved to esp_console_repl_task + * to preserve user expectations. Consider the following usage pattern: + * esp_console_start_repl(repl); + * printf("!!!ready!!!"); + * Users expect that when "!!!ready!!!" is printed, the console is already available. + * If linenoiseProbe() were moved to esp_console_repl_task, race conditions + * between threads combined with usleep() calls inside linenoiseProbe() could + * change this behavior. Currently, there is already a race between threads, + * but since esp_console_repl_task does not call any sleep functions, everything + * works as users expect. + */ int probe_status = linenoiseProbe(); if (probe_status) { /* zero indicates success */ @@ -159,7 +172,6 @@ void esp_console_repl_task(void *args) { esp_console_repl_universal_t *repl_conf = (esp_console_repl_universal_t *) args; esp_console_repl_com_t *repl_com = &repl_conf->repl_com; - const int uart_channel = repl_conf->uart_channel; /* Waiting for task notify. This happens when `esp_console_start_repl()` * function is called. */ @@ -173,6 +185,16 @@ void esp_console_repl_task(void *args) /* Change standard input and output of the task if the requested UART is * NOT the default one. This block will replace stdin, stdout and stderr. */ +#if CONFIG_LIBC_PICOLIBC + // TODO IDF-14901 + if (repl_com->_stdin) { + stdin = repl_com->_stdin; + stdout = stderr = repl_com->_stdout; + } else { + linenoise_init_with_global_stdio(); + } +#else + const int uart_channel = repl_conf->uart_channel; if (uart_channel != CONFIG_ESP_CONSOLE_UART_NUM) { char path[CONSOLE_PATH_MAX_LEN] = { 0 }; snprintf(path, CONSOLE_PATH_MAX_LEN, "/dev/uart/%d", uart_channel); @@ -181,6 +203,7 @@ void esp_console_repl_task(void *args) stdout = fopen(path, "w"); stderr = stdout; } +#endif /* Disable buffering on stdin of the current task. * If the console is ran on a different UART than the default one, @@ -232,6 +255,10 @@ void esp_console_repl_task(void *args) linenoiseFree(line); } +#if CONFIG_LIBC_PICOLIBC + linenoise_close_stdio(); +#endif + if (repl_com->state_mux != NULL) { xSemaphoreGive(repl_com->state_mux); } diff --git a/components/console/esp_console_repl_chip.c b/components/console/esp_console_repl_chip.c index 912fa90a66b..96132fa9843 100644 --- a/components/console/esp_console_repl_chip.c +++ b/components/console/esp_console_repl_chip.c @@ -252,9 +252,42 @@ esp_err_t esp_console_new_repl_uart(const esp_console_dev_uart_config_t *dev_con goto _exit; } +#if CONFIG_LIBC_PICOLIBC // TODO IDF-14901 +#if !CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#define tls_stdin linenoise_stdin +#define tls_stdout linenoise_stdout +#endif + extern __thread FILE *tls_stdin; + extern __thread FILE *tls_stdout; + + // Workaround for Picolibc to use thread-local stdio streams when the console is not the default one. + // Need to set linenoise_stdin/linenoise_stdout to correct values that will be used by the esp_console_repl_task + // before esp_console_setup_prompt() call, because it uses them. After that, we can restore the original values. + if (dev_config->channel != CONFIG_ESP_CONSOLE_UART_NUM) { + char path[CONSOLE_PATH_MAX_LEN] = { 0 }; + snprintf(path, CONSOLE_PATH_MAX_LEN, "/dev/uart/%d", dev_config->channel); + uart_repl->repl_com._stdin = fopen(path, "r"); + uart_repl->repl_com._stdout = fopen(path, "w"); + } + FILE *tmp_stdin = stdin; + FILE *tmp_stdout = stdout; + if (uart_repl->repl_com._stdin) { + tls_stdin = uart_repl->repl_com._stdin; + tls_stdout = uart_repl->repl_com._stdout; + } +#endif + // setup prompt esp_console_setup_prompt(repl_config->prompt, &uart_repl->repl_com); +#if CONFIG_LIBC_PICOLIBC // TODO IDF-14901 + if (uart_repl->repl_com._stdin) { + // Restore the original values of tls_stdin and tls_stdout just in case. + tls_stdin = tmp_stdin; + tls_stdout = tmp_stdout; + } +#endif + /* Fill the structure here as it will be used directly by the created task. */ uart_repl->uart_channel = dev_config->channel; uart_repl->repl_com.state = CONSOLE_REPL_STATE_INIT; diff --git a/components/console/linenoise/linenoise.c b/components/console/linenoise/linenoise.c index 4e051cf6a82..64fcf23a12d 100644 --- a/components/console/linenoise/linenoise.c +++ b/components/console/linenoise/linenoise.c @@ -124,6 +124,14 @@ #include #include #include "linenoise.h" +#if CONFIG_LIBC_PICOLIBC +#include +#endif + +#if CONFIG_LIBC_PICOLIBC && !CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +__thread FILE *linenoise_stdin; +__thread FILE *linenoise_stdout; +#endif #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_DEFAULT_MAX_LINE 4096 diff --git a/components/console/private_include/console_private.h b/components/console/private_include/console_private.h index cbcca4d4482..2e326fcb935 100644 --- a/components/console/private_include/console_private.h +++ b/components/console/private_include/console_private.h @@ -31,6 +31,10 @@ typedef enum { typedef struct { esp_console_repl_t repl_core; // base class +#if CONFIG_LIBC_PICOLIBC + FILE *_stdin; + FILE *_stdout; +#endif char prompt[CONSOLE_PROMPT_MAX_LEN]; // Prompt to be printed before each line repl_state_t state; SemaphoreHandle_t state_mux; diff --git a/components/console/private_include/console_stdio_private.h b/components/console/private_include/console_stdio_private.h new file mode 100644 index 00000000000..f7f4d46b171 --- /dev/null +++ b/components/console/private_include/console_stdio_private.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** + * This file provides thread-local storage for stdin/stdout streams when using + * picolibc to have thread-local stdio streams instead of global ones. + * It enables per-thread stdio redirection by: + * - Defining thread-local FILE* variables (tls_stdin, tls_stdout) + * - Redefining standard I/O macros (stdin, stdout, printf, scanf, etc.) to use TLS streams + * - Providing initialization and cleanup functions for TLS stdio streams + */ + +#pragma once +#include +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_LIBC_PICOLIBC && !CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#define tls_stdin linenoise_stdin +#define tls_stdout linenoise_stdout +#endif + +#if CONFIG_LIBC_PICOLIBC +extern __thread FILE *tls_stdin; +extern __thread FILE *tls_stdout; +#endif + +static inline void linenoise_init_with_global_stdio(void) +{ +#if CONFIG_LIBC_PICOLIBC + tls_stdin = stdin; + tls_stdout = stdout; +#endif +} + +static inline void linenoise_close_stdio(void) +{ +#if CONFIG_LIBC_PICOLIBC + if (tls_stdin != stdin) { + fclose(tls_stdin); + } + if (tls_stdout != stdout) { + fclose(tls_stdout); + } +#endif +} + +#if CONFIG_LIBC_PICOLIBC +#undef stdin +#define stdin tls_stdin + +#undef stdout +#define stdout tls_stdout + +#define printf(...) fprintf(tls_stdout, __VA_ARGS__) +#define vprintf(fmt, ap) vfprintf(tls_stdout, fmt, ap) +#ifdef putchar +#undef putchar +#endif +#define putchar(c) fputc((c), tls_stdout) +#define puts(s) fputs((s), tls_stdout) + +#define scanf(...) fscanf(tls_stdin, __VA_ARGS__) +#define vscanf(fmt, ap) vfscanf(tls_stdin, fmt, ap) +#ifdef getchar +#undef getchar +#endif +#define getchar() fgetc(tls_stdin) +#define gets(buf) fgets((buf), sizeof(buf), tls_stdin) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/console/test_apps/console/main/CMakeLists.txt b/components/console/test_apps/console/main/CMakeLists.txt index b253135b6cb..0039ab47aec 100644 --- a/components/console/test_apps/console/main/CMakeLists.txt +++ b/components/console/test_apps/console/main/CMakeLists.txt @@ -1,4 +1,10 @@ +set(priv_requires unity console) + +if(NOT CONFIG_IDF_TARGET_LINUX) + list(APPEND priv_requires esp_driver_uart) +endif() + idf_component_register(SRCS "test_app_main.c" "test_console.c" INCLUDE_DIRS "." - PRIV_REQUIRES unity console + PRIV_REQUIRES ${priv_requires} WHOLE_ARCHIVE) diff --git a/components/console/test_apps/console/main/test_app_main.c b/components/console/test_apps/console/main/test_app_main.c index 2336f50da53..c475fd72d13 100644 --- a/components/console/test_apps/console/main/test_app_main.c +++ b/components/console/test_apps/console/main/test_app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,9 @@ #include "unity_test_runner.h" #include "unity_test_utils_memory.h" #include +#if !CONFIG_IDF_TARGET_LINUX +#include "driver/uart.h" +#endif // Some resources are lazy allocated (newlib locks) in the console code, the threshold is left for that case #define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT (150) @@ -36,6 +39,15 @@ void app_main(void) struct timeval tv = { 0 }; gettimeofday(&tv, NULL); +#if !CONFIG_IDF_TARGET_LINUX + /* Preallocate UART1 memory */ + fileno(stdin); + uart_driver_install(UART_NUM_1, 256, 0, 0, NULL, 0); + FILE *f = fopen("/dev/uart/1", "rw"); + fclose(f); + uart_driver_delete(UART_NUM_1); +#endif + printf("Running console component tests\n"); unity_run_menu(); } diff --git a/components/console/test_apps/console/main/test_console.c b/components/console/test_apps/console/main/test_console.c index 71e96f12ea7..bd6bc371684 100644 --- a/components/console/test_apps/console/main/test_console.c +++ b/components/console/test_apps/console/main/test_console.c @@ -13,6 +13,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" +#if !CONFIG_IDF_TARGET_LINUX +#include "driver/uart.h" +#endif /* * NOTE: Most of these unit tests DO NOT work standalone. They require pytest to control @@ -404,3 +407,33 @@ TEST_CASE("esp console re-register commands", "[console][ignore]") TEST_ESP_OK(esp_console_start_repl(s_repl)); vTaskDelay(pdMS_TO_TICKS(5000)); } + +#if !CONFIG_IDF_TARGET_LINUX + +TEST_CASE("esp console repl custom_uart test", "[console][ignore]") +{ + set_leak_threshold(248); + + printf("Running repl on UART1\n"); + + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + uart_config.channel = UART_NUM_1; // Set UART1 for repl task + + TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); + + TEST_ESP_OK(esp_console_cmd_register(&s_quit_cmd)); + + TEST_ESP_OK(esp_console_start_repl(s_repl)); + + /* Wait a little for repl console initialization on UART1 */ + vTaskDelay(pdMS_TO_TICKS(300)); + + TEST_ESP_OK(esp_console_stop_repl(s_repl)); + + /* Let scheduler clean task internals */ + vTaskDelay(pdMS_TO_TICKS(50)); + + printf("ByeBye\r\n"); +} +#endif // !CONFIG_IDF_TARGET_LINUX From d2e01259753c3f17960e291ddf81ee02a4d3b776 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Sun, 30 Nov 2025 00:51:38 +0700 Subject: [PATCH 09/18] fix(iperf): fix incorrect test expectation logic --- .../ethernet/iperf/main/ethernet_iperf_main.c | 20 +++++++++++++++++++ examples/ethernet/iperf/pytest_eth_iperf.py | 15 ++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/examples/ethernet/iperf/main/ethernet_iperf_main.c b/examples/ethernet/iperf/main/ethernet_iperf_main.c index a1259dd0c1c..04155b54768 100644 --- a/examples/ethernet/iperf/main/ethernet_iperf_main.c +++ b/examples/ethernet/iperf/main/ethernet_iperf_main.c @@ -23,6 +23,8 @@ static const char *TAG = "eth_example"; static esp_eth_handle_t *s_eth_handles = NULL; static uint8_t s_eth_port_cnt = 0; +static SemaphoreHandle_t ip_got_sem; + #if CONFIG_EXAMPLE_STORE_HISTORY #define MOUNT_PATH "/data" @@ -43,8 +45,20 @@ static void initialize_filesystem(void) } #endif // CONFIG_EXAMPLE_STORE_HISTORY +static void got_ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + xSemaphoreGive(ip_got_sem); +} + void init_ethernet_and_netif(void) { + ip_got_sem = xSemaphoreCreateBinary(); + if (ip_got_sem == NULL) { + ESP_LOGE(TAG, "Failed to create semaphore"); + return; + } + ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(example_eth_init(&s_eth_handles, &s_eth_port_cnt)); @@ -71,9 +85,15 @@ void init_ethernet_and_netif(void) ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(s_eth_handles[i]))); } + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + for (int i = 0; i < s_eth_port_cnt; i++) { ESP_ERROR_CHECK(esp_eth_start(s_eth_handles[i])); } + + if (xSemaphoreTake(ip_got_sem, portMAX_DELAY) != pdTRUE) { + ESP_LOGE(TAG, "Timeout waiting for ETH IP"); + } } void app_main(void) diff --git a/examples/ethernet/iperf/pytest_eth_iperf.py b/examples/ethernet/iperf/pytest_eth_iperf.py index 36fcc53b356..5fa3a956e70 100644 --- a/examples/ethernet/iperf/pytest_eth_iperf.py +++ b/examples/ethernet/iperf/pytest_eth_iperf.py @@ -30,6 +30,12 @@ except ImportError: NO_BANDWIDTH_LIMIT = -1 # iperf send bandwidth is not limited +def get_ip_and_wait_prompt(dut: Dut) -> Any: + dut_ip = dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1) + dut.expect('iperf>') + return dut_ip + + class IperfTestUtilityEth(IperfUtility.IperfTestUtility): """iperf test implementation""" @@ -52,9 +58,7 @@ class IperfTestUtilityEth(IperfUtility.IperfTestUtility): except subprocess.CalledProcessError: pass self.dut.write('restart') - self.dut.expect("Type 'help' to get the list of commands.") - self.dut.expect('iperf>') - dut_ip = self.dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1) + dut_ip = get_ip_and_wait_prompt(self.dut) rssi = 0 return dut_ip, rssi @@ -73,12 +77,11 @@ def test_esp_eth_iperf( 2. compare with the pre-defined pass standard """ - # 1. wait for DUT - dut.expect_exact('iperf>') + # 1. wait for DUT to be ready + dut_ip = get_ip_and_wait_prompt(dut) # 2. preparing pc_iperf_log_file = os.path.join(dut.logdir, 'pc_iperf_log.md') - dut_ip = dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1) pc_nic_ip = get_host_ip4_by_dest_ip(dut_ip) test_result = { 'tcp_tx': IperfUtility.TestResult('tcp', 'tx', 'ethernet'), From 250db2464d6ef2aea5f6d43bbbce20312e88d6a5 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Sun, 30 Nov 2025 00:57:26 +0700 Subject: [PATCH 10/18] fix(icmp_echo): fix incorrect test expectation logic --- examples/protocols/icmp_echo/pytest_icmp_echo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/protocols/icmp_echo/pytest_icmp_echo.py b/examples/protocols/icmp_echo/pytest_icmp_echo.py index 3637c134be1..a56f2b649a3 100644 --- a/examples/protocols/icmp_echo/pytest_icmp_echo.py +++ b/examples/protocols/icmp_echo/pytest_icmp_echo.py @@ -83,6 +83,8 @@ def test_protocols_icmp_echo_ipv6_only(dut: Dut) -> None: logging.info(f'Connected AP with IPv6={ipv6}') interface_nr = dut.expect(r'Connected on interface: [a-z]{2}\d \((\d+)\)', timeout=30)[1].decode() + dut.expect_exact('esp>') + # ping our own address to simplify things dut.write('ping -I {} {} -c 5'.format(interface_nr, ipv6)) From a2840fb46aff3da1a019337a02d90a543b5a3c3d Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Sun, 30 Nov 2025 01:37:34 +0700 Subject: [PATCH 11/18] fix(tee): fix incorrect test expectation logic --- examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py b/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py index c8d7aba6064..80bf5a6ff09 100644 --- a/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py +++ b/examples/security/tee/tee_secure_ota/pytest_tee_secure_ota.py @@ -92,7 +92,7 @@ def test_examples_tee_secure_ota_example(dut: Dut) -> None: raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') host_ip = get_host_ip4_by_dest_ip(ip_address) - dut.expect('Returned from app_main', timeout=30) + dut.expect(f'{dut.target}>', timeout=30) # User OTA for last iteration if i == (iterations - 1): From 09d25aba629f7051eeac83ee450ea0bbfafc52a8 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Thu, 11 Dec 2025 10:13:50 +0700 Subject: [PATCH 12/18] fix(efuse): use proper headers in sources --- components/efuse/src/esp_efuse_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c index 853a36e4298..e9e470accbb 100644 --- a/components/efuse/src/esp_efuse_api.c +++ b/components/efuse/src/esp_efuse_api.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include "esp_efuse.h" #include "esp_efuse_utility.h" #include "soc/efuse_periph.h" From 7b1100db2d398e2c3ed7587f7d8f43fb85e8a349 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Thu, 11 Dec 2025 10:13:30 +0700 Subject: [PATCH 13/18] fix(newlib): adapt changes --- .../include/esp32h21/rom/libc_stubs.h | 15 +- .../lwip/port/hooks/lwip_default_hooks.c | 2 + components/newlib/CMakeLists.txt | 49 ++++-- components/newlib/Kconfig | 20 ++- components/newlib/platform_include/ctype.h | 41 +++++ .../newlib/platform_include/stdatomic.h | 20 +++ .../newlib/platform_include/sys/dirent.h | 70 -------- components/newlib/platform_include/sys/lock.h | 8 +- .../newlib/platform_include/sys/select.h | 4 + .../{src => priv_include}/string/local.h | 2 + components/newlib/sbom.yml | 2 +- components/newlib/src/assert.c | 3 +- components/newlib/src/esp_libc.lf | 21 +++ components/newlib/src/getentropy.c | 1 + ...sp32-spiram-rom-functions-c.lf => libc.lf} | 4 - components/newlib/src/newlib.lf | 11 -- components/newlib/src/newlib_init.c | 2 +- ...sp32-spiram-rom-functions-c.lf => libc.lf} | 0 .../newlib/src/picolibc/picolibc_init.c | 3 +- components/newlib/src/port/riscv/memcpy.c | 96 ++++++++--- components/newlib/src/port/riscv/memmove.c | 150 ++++++++++++++++ components/newlib/src/port/riscv/strcpy.c | 4 +- components/newlib/src/pthread.c | 6 +- components/newlib/src/reent_syscalls.c | 1 + components/newlib/src/string/memcmp.c | 3 +- components/newlib/src/string/memmove.c | 88 ---------- components/newlib/src/string/strncmp.c | 3 +- components/newlib/src/string/strncpy.c | 4 +- components/newlib/src/syscalls.c | 6 +- .../newlib/test_apps/.build-test-rules.yml | 7 - .../newlib/main/test_misaligned_access.c | 162 ++++++++++++++++++ .../test_apps/newlib/main/test_newlib.c | 1 + .../test_apps/no_rvfplib/CMakeLists.txt | 10 ++ .../newlib/test_apps/no_rvfplib/README.md | 6 + .../test_apps/no_rvfplib/main/CMakeLists.txt | 2 + .../test_apps/no_rvfplib/main/test_main.c | 8 + .../test_apps/no_rvfplib/sdkconfig.ci.default | 2 + components/soc/project_include.cmake | 16 +- 38 files changed, 587 insertions(+), 266 deletions(-) create mode 100644 components/newlib/platform_include/ctype.h create mode 100644 components/newlib/platform_include/stdatomic.h delete mode 100644 components/newlib/platform_include/sys/dirent.h rename components/newlib/{src => priv_include}/string/local.h (98%) create mode 100644 components/newlib/src/esp_libc.lf rename components/newlib/src/{esp32-spiram-rom-functions-c.lf => libc.lf} (97%) delete mode 100644 components/newlib/src/newlib.lf rename components/newlib/src/picolibc/{esp32-spiram-rom-functions-c.lf => libc.lf} (100%) create mode 100644 components/newlib/src/port/riscv/memmove.c delete mode 100644 components/newlib/src/string/memmove.c delete mode 100644 components/newlib/test_apps/.build-test-rules.yml create mode 100644 components/newlib/test_apps/newlib/main/test_misaligned_access.c create mode 100644 components/newlib/test_apps/no_rvfplib/CMakeLists.txt create mode 100644 components/newlib/test_apps/no_rvfplib/README.md create mode 100644 components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt create mode 100644 components/newlib/test_apps/no_rvfplib/main/test_main.c create mode 100644 components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default diff --git a/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h b/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h index 8b2b9ebd636..3b6db544958 100644 --- a/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h +++ b/components/esp_rom/esp32h21/include/esp32h21/rom/libc_stubs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -57,7 +57,6 @@ struct syscall_stub_table int (*_write_r)(struct _reent *r, int, const void *, int); int (*_lseek_r)(struct _reent *r, int, int, int); int (*_read_r)(struct _reent *r, int, void *, int); -#ifdef _RETARGETABLE_LOCKING void (*_retarget_lock_init)(_LOCK_T *lock); void (*_retarget_lock_init_recursive)(_LOCK_T *lock); void (*_retarget_lock_close)(_LOCK_T lock); @@ -68,18 +67,6 @@ struct syscall_stub_table int (*_retarget_lock_try_acquire_recursive)(_LOCK_T lock); void (*_retarget_lock_release)(_LOCK_T lock); void (*_retarget_lock_release_recursive)(_LOCK_T lock); -#else - void (*_lock_init)(_lock_t *lock); - void (*_lock_init_recursive)(_lock_t *lock); - void (*_lock_close)(_lock_t *lock); - void (*_lock_close_recursive)(_lock_t *lock); - void (*_lock_acquire)(_lock_t *lock); - void (*_lock_acquire_recursive)(_lock_t *lock); - int (*_lock_try_acquire)(_lock_t *lock); - int (*_lock_try_acquire_recursive)(_lock_t *lock); - void (*_lock_release)(_lock_t *lock); - void (*_lock_release_recursive)(_lock_t *lock); -#endif int (*_printf_float)(struct _reent *data, void *pdata, FILE * fp, int (*pfunc) (struct _reent *, FILE *, const char *, size_t len), va_list * ap); int (*_scanf_float) (struct _reent *rptr, void *pdata, FILE *fp, va_list *ap); void (*__assert_func) (const char *file, int line, const char * func, const char *failedexpr) __attribute__((noreturn)); diff --git a/components/lwip/port/hooks/lwip_default_hooks.c b/components/lwip/port/hooks/lwip_default_hooks.c index 180c15a632d..1ec6e75814f 100644 --- a/components/lwip/port/hooks/lwip_default_hooks.c +++ b/components/lwip/port/hooks/lwip_default_hooks.c @@ -11,7 +11,9 @@ #include "esp_log.h" #include +#ifndef __weak #define __weak __attribute__((weak)) +#endif /** * Default lwip behavior is to silence LWIP_ERROR() if LWIP_DEBUG is not set. diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index 29363db53ef..658fa4c85f8 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -39,18 +39,19 @@ endif() if(CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS) list(APPEND srcs - "src/string/memcmp.c" - "src/string/memmove.c" - "src/string/strncmp.c" - "src/string/strncpy.c" "src/port/riscv/memcpy.c" + "src/port/riscv/memmove.c" + "src/string/memcmp.c" "src/port/riscv/strcpy.c" + "src/string/strncpy.c" + "src/string/strncmp.c" "src/port/riscv/strcmp.S") - list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memcmp_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memcpy_impl") list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memmove_impl") - list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncmp_impl") - list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncpy_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_memcmp_impl") list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strcpy_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncpy_impl") + list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strncmp_impl") list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_strcmp_impl") endif() @@ -70,21 +71,28 @@ else() endif() endif() -list(APPEND ldfragments "src/newlib.lf" "src/system_libs.lf") +set(ldfragments "") +list(APPEND ldfragments "src/esp_libc.lf" "src/system_libs.lf") -if(CONFIG_SPIRAM_CACHE_WORKAROUND) - if(CONFIG_LIBC_NEWLIB) - list(APPEND ldfragments src/esp32-spiram-rom-functions-c.lf) - list(APPEND ldfragments src/libm.lf) - else() - list(APPEND ldfragments src/picolibc/esp32-spiram-rom-functions-c.lf) +if(CONFIG_LIBC_NEWLIB) + list(APPEND ldfragments src/libc.lf) + list(APPEND ldfragments src/libm.lf) +else() + list(APPEND ldfragments src/picolibc/libc.lf) +endif() + +set(priv_reqs soc spi_flash) + +if(IDF_BUILD_V2) + if(CONFIG_VFS_SUPPORT_IO) + list(APPEND priv_reqs vfs) endif() endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS platform_include PRIV_INCLUDE_DIRS priv_include - PRIV_REQUIRES soc spi_flash + PRIV_REQUIRES "${priv_reqs}" LDFRAGMENTS "${ldfragments}") # Toolchain libraries require code defined in this component @@ -98,6 +106,17 @@ if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) PROPERTIES COMPILE_FLAGS "-mno-disable-hardware-atomics") endif() +if(CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS) + # TODO GCC-419 and IDF-13089: cleanup files + set_source_files_properties("src/string/memcmp.c" + "src/string/strncmp.c" + "src/string/strncpy.c" + "src/port/riscv/memcpy.c" + "src/port/riscv/memmove.c" + "src/port/riscv/strcpy.c" + PROPERTIES COMPILE_FLAGS -O2) +endif() + # Forces the linker to include heap, syscall, pthread, assert, and retargetable locks from this component, # instead of the implementations provided by newlib. list(APPEND EXTRA_LINK_FLAGS "-u esp_libc_include_heap_impl") diff --git a/components/newlib/Kconfig b/components/newlib/Kconfig index 17e9d383581..2b333eebedb 100644 --- a/components/newlib/Kconfig +++ b/components/newlib/Kconfig @@ -174,13 +174,13 @@ menu "LibC" config LIBC_OPTIMIZED_MISALIGNED_ACCESS bool "Use performance-optimized memXXX/strXXX functions on misaligned memory access" - default n + default y depends on ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY help Enables performance-optimized implementations of memory and string functions when handling misaligned memory. - This increases the image size by ~1000 bytes. + Require approximately 800–1000 bytes of IRAM. Optimized functions include: - memcpy @@ -189,6 +189,22 @@ menu "LibC" - str[n]cpy - str[n]cmp + config LIBC_ASSERT_BUFFER_SIZE + int "Assert message buffer size" + range 100 2048 + default 200 + help + Size of the buffer used to format assert failure messages. + + When assertions fail, the system formats a message containing the function name, + file name, line number, and the failed expression. This option controls the + maximum length of this message. + + If you encounter truncated assert messages (especially with C++ templates or + long function names), increase this value. The default value of 200 bytes + should be sufficient for most cases, but complex template expressions may + require larger buffers. + endmenu # LibC config STDATOMIC_S32C1I_SPIRAM_WORKAROUND diff --git a/components/newlib/platform_include/ctype.h b/components/newlib/platform_include/ctype.h new file mode 100644 index 00000000000..18eb252128f --- /dev/null +++ b/components/newlib/platform_include/ctype.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include_next + +#if CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY +#ifndef _U +#define _U __CTYPE_UPPER +#endif + +#ifndef _L +#define _L __CTYPE_LOWER +#endif + +#ifndef _N +#define _N __CTYPE_DIGIT +#endif + +#ifndef _S +#define _S __CTYPE_SPACE +#endif + +#ifndef _P +#define _P __CTYPE_PUNCT +#endif + +#ifndef _C +#define _C __CTYPE_CNTRL +#endif + +#ifndef _X +#define _X __CTYPE_HEX +#endif + +#ifndef _B +#define _B __CTYPE_BLANK +#endif +#endif diff --git a/components/newlib/platform_include/stdatomic.h b/components/newlib/platform_include/stdatomic.h new file mode 100644 index 00000000000..6ec881daabb --- /dev/null +++ b/components/newlib/platform_include/stdatomic.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include_next + +/* The ATOMIC_VAR_INIT macro was deprecated in: + * - C17 + * - C++20 + * and removed in subsequent standards. + * Since users may change the standard version for their projects, + * IDF should remain compatible across different standards. + */ +#if __STDC_VERSION__ > 201710L || __cplusplus > 202002L +# ifndef ATOMIC_VAR_INIT +# define ATOMIC_VAR_INIT(val) (val) +# endif +#endif diff --git a/components/newlib/platform_include/sys/dirent.h b/components/newlib/platform_include/sys/dirent.h deleted file mode 100644 index 2643ddc9544..00000000000 --- a/components/newlib/platform_include/sys/dirent.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifdef __clang__ // TODO LLVM-330 -#pragma once - -#include -#include -#include - -/** - * This header file provides POSIX-compatible definitions of directory - * access data types. Starting with newlib 3.3, related functions are defined - * in 'dirent.h' bundled with newlib. - * See http://pubs.opengroup.org/onlinepubs/7908799/xsh/dirent.h.html - * for reference. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Opaque directory structure - */ -typedef struct { - uint16_t dd_vfs_idx; /*!< VFS index, not to be used by applications */ - uint16_t dd_rsv; /*!< field reserved for future extension */ - /* remaining fields are defined by VFS implementation */ -} DIR; - -/** - * @brief Directory entry structure - */ -struct dirent { - ino_t d_ino; /*!< file number */ - uint8_t d_type; /*!< not defined in POSIX, but present in BSD and Linux */ -#define DT_UNKNOWN 0 -#define DT_REG 1 -#define DT_DIR 2 -#if __BSD_VISIBLE -#define MAXNAMLEN 255 - char d_name[MAXNAMLEN + 1]; /*!< zero-terminated file name */ -#else - char d_name[256]; -#endif -}; - -DIR* opendir(const char* name); -struct dirent* readdir(DIR* pdir); -long telldir(DIR* pdir); -void seekdir(DIR* pdir, long loc); -void rewinddir(DIR* pdir); -int closedir(DIR* pdir); -int readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_dirent); -int scandir(const char *dirname, struct dirent ***out_dirlist, - int (*select_func)(const struct dirent *), - int (*cmp_func)(const struct dirent **, const struct dirent **)); -int alphasort(const struct dirent **d1, const struct dirent **d2); - -#ifdef __cplusplus -} -#endif - -#else // __clang__ TODO: IDF-10675 -#include_next -#include -#endif // __clang__ diff --git a/components/newlib/platform_include/sys/lock.h b/components/newlib/platform_include/sys/lock.h index aed4d2c1832..96742321364 100644 --- a/components/newlib/platform_include/sys/lock.h +++ b/components/newlib/platform_include/sys/lock.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,7 @@ extern "C" { #endif -#ifdef _RETARGETABLE_LOCKING +#if defined(_RETARGETABLE_LOCKING) || defined(CONFIG_LIBC_PICOLIBC) /* Actual platfrom-specific definition of struct __lock. * The size here should be sufficient for a FreeRTOS mutex. @@ -52,10 +52,6 @@ int _lock_try_acquire_recursive(_lock_t *plock); void _lock_release(_lock_t *plock); void _lock_release_recursive(_lock_t *plock); -#if CONFIG_LIBC_PICOLIBC -#define __lock_try_acquire(lock) _lock_try_acquire(&(lock)) -#define __lock_try_acquire_recursive(lock) _lock_try_acquire_recursive(&(lock)) -#endif // CONFIG_LIBC_PICOLIBC #endif // _RETARGETABLE_LOCKING #ifdef __cplusplus diff --git a/components/newlib/platform_include/sys/select.h b/components/newlib/platform_include/sys/select.h index e4d828b7110..2eeab9092f6 100644 --- a/components/newlib/platform_include/sys/select.h +++ b/components/newlib/platform_include/sys/select.h @@ -26,6 +26,10 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct #endif // fd_set +#if __BSD_VISIBLE && !defined(fds_bits) +#define fds_bits __fds_bits +#endif + #if defined(FD_ISSET) || defined(FD_SET) || defined(FD_CLR) #undef FD_SET #undef FD_CLR diff --git a/components/newlib/src/string/local.h b/components/newlib/priv_include/string/local.h similarity index 98% rename from components/newlib/src/string/local.h rename to components/newlib/priv_include/string/local.h index bfc1260efc2..d6df832838c 100644 --- a/components/newlib/src/string/local.h +++ b/components/newlib/priv_include/string/local.h @@ -22,7 +22,9 @@ * to avoid small performance penalties (if they are not zero). */ #define UNALIGNED_X(X) ((long)X & (sizeof (long) - 1)) +#ifndef _HAVE_HW_MISALIGNED_ACCESS #define _HAVE_HW_MISALIGNED_ACCESS (__riscv_misaligned_fast || __riscv_misaligned_slow) +#endif #if _HAVE_HW_MISALIGNED_ACCESS /* Hardware performs unaligned operations with little diff --git a/components/newlib/sbom.yml b/components/newlib/sbom.yml index 6c88c6fa0c5..a269a621e0e 100644 --- a/components/newlib/sbom.yml +++ b/components/newlib/sbom.yml @@ -4,4 +4,4 @@ originator: 'Organization: Espressif Systems (Shanghai) CO LTD' description: An open-source C standard library implementation with additional features and patches from Espressif. virtpackages: - sbom_newlibc.yml - - sbom_picolibc.yml== + - sbom_picolibc.yml diff --git a/components/newlib/src/assert.c b/components/newlib/src/assert.c index 9bdb2f66ccb..fbe3540d8e0 100644 --- a/components/newlib/src/assert.c +++ b/components/newlib/src/assert.c @@ -9,6 +9,7 @@ #include "esp_system.h" #include "soc/soc_memory_layout.h" #include "esp_private/cache_utils.h" +#include "sdkconfig.h" #define ASSERT_STR "assert failed: " #define CACHE_DISABLED_STR "" @@ -39,7 +40,7 @@ void __attribute__((noreturn)) __assert_func(const char *file, int line, const c esp_system_abort(buff); #else char addr[11] = { 0 }; - char buff[200]; + char buff[CONFIG_LIBC_ASSERT_BUFFER_SIZE]; char lbuf[5]; uint32_t rem_len = sizeof(buff) - 1; uint32_t off = 0; diff --git a/components/newlib/src/esp_libc.lf b/components/newlib/src/esp_libc.lf new file mode 100644 index 00000000000..d111c364f43 --- /dev/null +++ b/components/newlib/src/esp_libc.lf @@ -0,0 +1,21 @@ +[mapping:esp_libc] +archive: libnewlib.a +entries: + if LIBC_OPTIMIZED_MISALIGNED_ACCESS = y: + memcpy (noflash) + memmove (noflash) + memcmp (noflash) + strcpy (noflash) + strncpy (noflash) + strcmp (noflash) + strncmp (noflash) + if LIBC_MISC_IN_IRAM = y: + if HEAP_PLACE_FUNCTION_INTO_FLASH = n: + heap (noflash) + abort (noflash) + assert (noflash) + stdatomic (noflash) + if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y: + stdatomic_s32c1i (noflash) + if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y: + stdatomic_s32c1i (noflash) diff --git a/components/newlib/src/getentropy.c b/components/newlib/src/getentropy.c index 530a5964cc6..850ae4e1cf5 100644 --- a/components/newlib/src/getentropy.c +++ b/components/newlib/src/getentropy.c @@ -6,6 +6,7 @@ #include #include +#include int getentropy(void *buffer, size_t length) { diff --git a/components/newlib/src/esp32-spiram-rom-functions-c.lf b/components/newlib/src/libc.lf similarity index 97% rename from components/newlib/src/esp32-spiram-rom-functions-c.lf rename to components/newlib/src/libc.lf index bd5b09fa810..05fdef23062 100644 --- a/components/newlib/src/esp32-spiram-rom-functions-c.lf +++ b/components/newlib/src/libc.lf @@ -3,10 +3,6 @@ # and/or applications may assume that because these functions normally are in ROM, they are accessible even when flash is # inaccessible. To work around this, this ld fragment places these functions in RAM instead. If the ROM functions are used, # these defines do nothing, so they can still be included in that situation. -# -# -# Note: the only difference between esp32-spiram-rom-functions-c.lf -# and esp32-spiram-rom-functions-psram-workaround.lf is the archive name. [mapping:libc] archive: diff --git a/components/newlib/src/newlib.lf b/components/newlib/src/newlib.lf deleted file mode 100644 index 7ca47a0b9b7..00000000000 --- a/components/newlib/src/newlib.lf +++ /dev/null @@ -1,11 +0,0 @@ -[mapping:newlib] -archive: libnewlib.a -entries: - if LIBC_MISC_IN_IRAM = y: - if HEAP_PLACE_FUNCTION_INTO_FLASH = n: - heap (noflash) - abort (noflash) - assert (noflash) - stdatomic (noflash) - if STDATOMIC_S32C1I_SPIRAM_WORKAROUND = y: - stdatomic_s32c1i (noflash) diff --git a/components/newlib/src/newlib_init.c b/components/newlib/src/newlib_init.c index f4a250756fb..f65d94d94e6 100644 --- a/components/newlib/src/newlib_init.c +++ b/components/newlib/src/newlib_init.c @@ -101,7 +101,7 @@ static struct syscall_stub_table s_stub_table = { ._lock_release = &_lock_release, ._lock_release_recursive = &_lock_release_recursive, #endif -#ifdef CONFIG_NEWLIB_NANO_FORMAT +#ifdef CONFIG_LIBC_NEWLIB_NANO_FORMAT ._printf_float = &_printf_float, ._scanf_float = &_scanf_float, #else diff --git a/components/newlib/src/picolibc/esp32-spiram-rom-functions-c.lf b/components/newlib/src/picolibc/libc.lf similarity index 100% rename from components/newlib/src/picolibc/esp32-spiram-rom-functions-c.lf rename to components/newlib/src/picolibc/libc.lf diff --git a/components/newlib/src/picolibc/picolibc_init.c b/components/newlib/src/picolibc/picolibc_init.c index 07540a4e554..c623a815a28 100644 --- a/components/newlib/src/picolibc/picolibc_init.c +++ b/components/newlib/src/picolibc/picolibc_init.c @@ -13,9 +13,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include "esp_newlib.h" diff --git a/components/newlib/src/port/riscv/memcpy.c b/components/newlib/src/port/riscv/memcpy.c index bbee1d3f026..fbc6c1df9f3 100644 --- a/components/newlib/src/port/riscv/memcpy.c +++ b/components/newlib/src/port/riscv/memcpy.c @@ -18,14 +18,11 @@ #include #include -#include "esp_attr.h" -#include "../../string/local.h" +#include "string/local.h" #define unlikely(X) __builtin_expect (!!(X), 0) -IRAM_ATTR void * -__attribute__((optimize("-Os"))) __inhibit_loop_to_libcall memcpy(void *__restrict aa, const void *__restrict bb, size_t n) { @@ -65,29 +62,80 @@ small: if (unlikely(lend - la > 8)) { while (lend - la > 8) { - long b0 = *lb++; - long b1 = *lb++; - long b2 = *lb++; - long b3 = *lb++; - long b4 = *lb++; - long b5 = *lb++; - long b6 = *lb++; - long b7 = *lb++; - long b8 = *lb++; - *la++ = b0; - *la++ = b1; - *la++ = b2; - *la++ = b3; - *la++ = b4; - *la++ = b5; - *la++ = b6; - *la++ = b7; - *la++ = b8; + /* + * long b0 = *lb++; + * long b1 = *lb++; + * long b2 = *lb++; + * long b3 = *lb++; + * long b4 = *lb++; + * long b5 = *lb++; + * long b6 = *lb++; + * long b7 = *lb++; + * long b8 = *lb++; + * *la++ = b0; + * *la++ = b1; + * *la++ = b2; + * *la++ = b3; + * *la++ = b4; + * *la++ = b5; + * *la++ = b6; + * *la++ = b7; + * *la++ = b8; + */ + long src0, src1, src2, src3; + long src4, src5, src6, src7; + long src8; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%10)\n" // scr0 = lb[0]; + "lw %1, 4(%10)\n" // scr1 = lb[1]; + "lw %2, 8(%10)\n" // scr2 = lb[2]; + "lw %3, 12(%10)\n" // scr3 = lb[3]; + "lw %4, 16(%10)\n" // scr4 = lb[4]; + "lw %5, 20(%10)\n" // scr5 = lb[5]; + "lw %6, 24(%10)\n" // scr6 = lb[6]; + "lw %7, 28(%10)\n" // scr7 = lb[7]; + "lw %8, 32(%10)\n" // scr8 = lb[8]; + "addi %9, %9, 36\n" // la += 8 * 9; + "addi %10, %10, 36\n" // lb += 8 * 9; + "sw %0, -36(%9)\n" // *(la - 9) = src; + "sw %1, -32(%9)\n" // *(la - 8) = src; + "sw %2, -28(%9)\n" // *(la - 7) = src; + "sw %3, -24(%9)\n" // *(la - 6) = src; + "sw %4, -20(%9)\n" // *(la - 5) = src; + "sw %5, -16(%9)\n" // *(la - 4) = src; + "sw %6, -12(%9)\n" // *(la - 3) = src; + "sw %7, -8(%9)\n" // *(la - 2) = src; + "sw %8, -4(%9)\n" // *(la - 1) = src; + : "=r"(src0), "=r"(src1), "=r"(src2), "=r"(src3), + "=r"(src4), "=r"(src5), "=r"(src6), "=r"(src7), + "=r"(src8), + "+r"(la), "+r"(lb) + :: "memory"); } } - while (la < lend) { - BODY(la, lb, long); + /* + * BODY(la, lb, long); + */ + long src0; +#ifdef __OPTIMIZE_SIZE__ +#error "Enabled Os optimization may not work properly for DIG-694" + /* + * Replacing the string: + * *la++ = tt; + * To: + * "addi %2, %4, 4\n" // la++; + * "sw %0, -4(%4)\n" // *(la-1) = src0; + * May break some optimizations and slightly reduce performance. + */ +#endif + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%1)\n" // long src0 = *lb; + "addi %1, %1, 4\n" // lb++; + "addi %2, %2, 4\n" // la++; + "sw %0, -4(%2)\n" // *(la-1) = src0; + : "=&r"(src0), "+r"(lb), "+r"(la) + :: "memory"); } a = (char *)la; diff --git a/components/newlib/src/port/riscv/memmove.c b/components/newlib/src/port/riscv/memmove.c new file mode 100644 index 00000000000..3b5d5568a6b --- /dev/null +++ b/components/newlib/src/port/riscv/memmove.c @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 1994-2009 Red Hat, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND Apache-2.0 + * + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + */ +#include +#include <_ansi.h> +#include +#include +#include "string/local.h" + +void * +__inhibit_loop_to_libcall +memmove(void *dst_void, + const void *src_void, + size_t length) +{ + char *dst = dst_void; + const char *src = src_void; + long *aligned_dst; + const long *aligned_src; + + if (src < dst && dst < src + length) { + /* Destructive overlap...have to copy backwards */ + src += length; + dst += length; + + if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* Copy one long word at a time if possible. */ + while (!TOO_SMALL_LITTLE_BLOCK(length)) { + /* + * const long src0 = *--aligned_src; + * *--aligned_dst = src0; + * length -= LITTLE_BLOCK_SIZE; + */ + long src0; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, -4(%1)\n" // src0 = *(aligned_src - 1); + "addi %1, %1, -4\n" // aligned_src--; + "addi %2, %2, -4\n" // aligned_dst--; + "addi %3, %3, -4\n" // length -= LITTLE_BLOCK_SIZE; + "sw %0, 0(%2)\n" // aligned_dst = src0; + : "=&r"(src0), "+r"(aligned_src), "+r"(aligned_dst), "+r"(length) + :: "memory"); + } + + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (length--) { + *--dst = *--src; + } + } else { + /* Use optimizing algorithm for a non-destructive copy to closely + match memcpy. If the size is small or either SRC or DST is unaligned, + then punt into the byte copy loop. This should be rare. */ + if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { + aligned_dst = (long*)dst; + aligned_src = (long*)src; + + /* Copy 8X long words at a time if possible. */ + while (length >= BIG_BLOCK_SIZE * 2) { + /* + * const long src0 = *aligned_src++; + * const long src1 = *aligned_src++; + * const long src2 = *aligned_src++; + * const long src3 = *aligned_src++; + * const long src4 = *aligned_src++; + * const long src5 = *aligned_src++; + * const long src6 = *aligned_src++; + * const long src7 = *aligned_src++; + * *aligned_dst++ = src0; + * *aligned_dst++ = src1; + * *aligned_dst++ = src2; + * *aligned_dst++ = src3; + * *aligned_dst++ = src4; + * *aligned_dst++ = src5; + * *aligned_dst++ = src6; + * *aligned_dst++ = src7; + */ + long src0, src1, src2, src3; + long src4, src5, src6, src7; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%8)\n" // src0 = aligned_src[0]; + "lw %1, 4(%8)\n" // src1 = aligned_src[1]; + "lw %2, 8(%8)\n" // src2 = aligned_src[2]; + "lw %3, 12(%8)\n" // src3 = aligned_src[3]; + "lw %4, 16(%8)\n" // src4 = aligned_src[4]; + "lw %5, 20(%8)\n" // src5 = aligned_src[5]; + "lw %6, 24(%8)\n" // src6 = aligned_src[6]; + "lw %7, 28(%8)\n" // src7 = aligned_src[7]; + "addi %8, %8, 32\n" // aligned_src += BIG_BLOCK_SIZE * 2; + "addi %9, %9, 32\n" // aligned_dst += BIG_BLOCK_SIZE * 2; + "addi %10, %10, -32\n" // length -= BIG_BLOCK_SIZE * 2; + "sw %0, -32(%9)\n" // *(aligned_dst - 8) = src0; + "sw %1, -28(%9)\n" // *(aligned_dst - 7) = src1; + "sw %2, -24(%9)\n" // *(aligned_dst - 6) = src2; + "sw %3, -20(%9)\n" // *(aligned_dst - 5) = src3; + "sw %4, -16(%9)\n" // *(aligned_dst - 4) = src4; + "sw %5, -12(%9)\n" // *(aligned_dst - 3) = src5; + "sw %6, -8(%9)\n" // *(aligned_dst - 2) = src6; + "sw %7, -4(%9)\n" // *(aligned_dst - 1) = src7; + : "=r"(src0), "=r"(src1), "=r"(src2), "=r"(src3), + "=r"(src4), "=r"(src5), "=r"(src6), "=r"(src7), + "+r"(aligned_src), "+r"(aligned_dst), "+r"(length) + :: "memory"); + } + + /* Copy one long word at a time if possible. */ + while (!TOO_SMALL_LITTLE_BLOCK(length)) { + /* + * const long src0 = *aligned_src++; + * *aligned_dst++ = src0; + * length -= LITTLE_BLOCK_SIZE; + */ + long src0; + /* DIG-694: need at least 2 instructions between lw and sw */ + asm volatile("lw %0, 0(%1)\n" // long src0 = *aligned_src; + "addi %1, %1, 4\n" // aligned_src++; + "addi %2, %2, 4\n" // aligned_dst++; + "addi %3, %3, -4\n" // length -= LITTLE_BLOCK_SIZE; + "sw %0, -4(%2)\n" // *(aligned_dst-1) = src0; + : "=&r"(src0), "+r"(aligned_src), "+r"(aligned_dst), "+r"(length) + :: "memory"); + } + + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; + } + + while (length--) { + *dst++ = *src++; + } + } + + return dst_void; +} + +// Hook to force the linker to include this file +void esp_libc_include_memmove_impl(void) +{ +} diff --git a/components/newlib/src/port/riscv/strcpy.c b/components/newlib/src/port/riscv/strcpy.c index 361a04baa1c..76bda0d3909 100644 --- a/components/newlib/src/port/riscv/strcpy.c +++ b/components/newlib/src/port/riscv/strcpy.c @@ -23,6 +23,7 @@ __attribute__((always_inline)) static inline unsigned long __newlib__libc_detect_null(unsigned long w) { + /* coverity[result_independent_of_operands] */ unsigned long mask = 0x7f7f7f7f; if (sizeof(long) == 8) { mask = ((mask << 16) << 16) | mask; @@ -30,7 +31,6 @@ unsigned long __newlib__libc_detect_null(unsigned long w) return ~(((w & mask) + mask) | w | mask); } -__attribute__((optimize("-Os"))) char *strcpy(char *dst, const char *src) { char *dst0 = dst; @@ -44,6 +44,7 @@ char *strcpy(char *dst, const char *src) const long *lsrc = (const long *)src; while (!__newlib__libc_detect_null(*lsrc)) { + /* DIG-694: there are enough instructions between lw and sw after compiler unrolls the loop */ *ldst++ = *lsrc++; } @@ -87,6 +88,7 @@ out: return dst0; } + /* coverity[unreachable] */ char ch; do { ch = *src; diff --git a/components/newlib/src/pthread.c b/components/newlib/src/pthread.c index 13da80d7d50..81ffb2c2179 100644 --- a/components/newlib/src/pthread.c +++ b/components/newlib/src/pthread.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include "esp_log.h" const static char *TAG = "esp32_asio_pthread"; @@ -13,7 +14,7 @@ int pthread_setcancelstate(int state, int *oldstate) return 0; } -// This functions (pthread_sigmask(), sigfillset) are called from ASIO::signal_blocker to temporarily silence signals +// This functions (pthread_sigmask(), sigfillset) might be called from external libs to temporarily silence signals // Since signals are not yet supported in ESP pthread these functions serve as no-ops // int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset) @@ -22,6 +23,8 @@ int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict os return 0; } +// picolibc has sigfillset macro in signal.h +#if !CONFIG_LIBC_PICOLIBC int sigfillset(sigset_t *what) { ESP_LOGD(TAG, "%s: Signals not supported in ESP pthread", __func__); @@ -30,6 +33,7 @@ int sigfillset(sigset_t *what) } return 0; } +#endif /* !CONFIG_LIBC_PICOLIBC */ void esp_libc_include_pthread_impl(void) { diff --git a/components/newlib/src/reent_syscalls.c b/components/newlib/src/reent_syscalls.c index 72f3a4ec181..a0362229906 100644 --- a/components/newlib/src/reent_syscalls.c +++ b/components/newlib/src/reent_syscalls.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sdkconfig.h" #include "esp_rom_uart.h" #include "esp_system_console.h" diff --git a/components/newlib/src/string/memcmp.c b/components/newlib/src/string/memcmp.c index 0a26ca8cd4e..4445d09da21 100644 --- a/components/newlib/src/string/memcmp.c +++ b/components/newlib/src/string/memcmp.c @@ -6,9 +6,8 @@ * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD */ #include -#include "local.h" +#include "string/local.h" -__attribute__((optimize("-Os"))) int memcmp(const void *m1, const void *m2, diff --git a/components/newlib/src/string/memmove.c b/components/newlib/src/string/memmove.c deleted file mode 100644 index 57071ddc096..00000000000 --- a/components/newlib/src/string/memmove.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SPDX-FileCopyrightText: 1994-2009 Red Hat, Inc. - * - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND Apache-2.0 - * - * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD - */ -#include -#include <_ansi.h> -#include -#include -#include "local.h" - -__attribute__((optimize("-Os"))) -void * -__inhibit_loop_to_libcall -memmove(void *dst_void, - const void *src_void, - size_t length) -{ - char *dst = dst_void; - const char *src = src_void; - long *aligned_dst; - const long *aligned_src; - - if (src < dst && dst < src + length) { - /* Destructive overlap...have to copy backwards */ - src += length; - dst += length; - - if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { - aligned_dst = (long*)dst; - aligned_src = (long*)src; - - /* Copy one long word at a time if possible. */ - while (!TOO_SMALL_LITTLE_BLOCK(length)) { - *--aligned_dst = *--aligned_src; - length -= LITTLE_BLOCK_SIZE; - } - - /* Pick up any residual with a byte copier. */ - dst = (char*)aligned_dst; - src = (char*)aligned_src; - } - - while (length--) { - *--dst = *--src; - } - } else { - /* Use optimizing algorithm for a non-destructive copy to closely - match memcpy. If the size is small or either SRC or DST is unaligned, - then punt into the byte copy loop. This should be rare. */ - if (!TOO_SMALL_LITTLE_BLOCK(length) && !UNALIGNED_X_Y(src, dst)) { - aligned_dst = (long*)dst; - aligned_src = (long*)src; - - /* Copy 4X long words at a time if possible. */ - while (!TOO_SMALL_BIG_BLOCK(length)) { - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - *aligned_dst++ = *aligned_src++; - length -= BIG_BLOCK_SIZE; - } - - /* Copy one long word at a time if possible. */ - while (!TOO_SMALL_LITTLE_BLOCK(length)) { - *aligned_dst++ = *aligned_src++; - length -= LITTLE_BLOCK_SIZE; - } - - /* Pick up any residual with a byte copier. */ - dst = (char*)aligned_dst; - src = (char*)aligned_src; - } - - while (length--) { - *dst++ = *src++; - } - } - - return dst_void; -} - -// Hook to force the linker to include this file -void esp_libc_include_memmove_impl(void) -{ -} diff --git a/components/newlib/src/string/strncmp.c b/components/newlib/src/string/strncmp.c index f0efd62189e..ed71b484e7d 100644 --- a/components/newlib/src/string/strncmp.c +++ b/components/newlib/src/string/strncmp.c @@ -7,9 +7,8 @@ */ #include #include -#include "local.h" +#include "string/local.h" -__attribute__((optimize("-Os"))) int strncmp(const char *s1, const char *s2, diff --git a/components/newlib/src/string/strncpy.c b/components/newlib/src/string/strncpy.c index 5821e1997be..0916244d354 100644 --- a/components/newlib/src/string/strncpy.c +++ b/components/newlib/src/string/strncpy.c @@ -7,9 +7,8 @@ */ #include #include -#include "local.h" +#include "string/local.h" -__attribute__((optimize("-Os"))) char * strncpy(char *__restrict dst0, const char *__restrict src0, @@ -29,6 +28,7 @@ strncpy(char *__restrict dst0, sized copies. */ while (!TOO_SMALL_LITTLE_BLOCK(count) && !DETECT_NULL(*aligned_src)) { count -= sizeof(long int); + /* DIG-694: there are enough instructions between lw and sw after compiler unrolls the loop */ *aligned_dst++ = *aligned_src++; } diff --git a/components/newlib/src/syscalls.c b/components/newlib/src/syscalls.c index d9dbe9e85af..b4ecf1f2fe9 100644 --- a/components/newlib/src/syscalls.c +++ b/components/newlib/src/syscalls.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "esp_attr.h" #if CONFIG_LIBC_PICOLIBC @@ -83,7 +84,7 @@ int rename(const char *src, const char *dst) int isatty(int fd) { - struct stat buf; + struct stat buf = {0}; if (_fstat_r(__getreent(), fd, &buf) < 0) { return 0; @@ -109,6 +110,7 @@ int getpid() { return _getpid_r(__getreent()); } + #endif // CONFIG_LIBC_PICOLIBC void _exit(int __status) @@ -121,6 +123,7 @@ int fstat(int fd, struct stat *st) return _fstat_r(__getreent(), fd, st); } +#if !CONFIG_LIBC_PICOLIBC #if CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM IRAM_ATTR #endif @@ -128,6 +131,7 @@ int raise(int sig) { return _raise_r(__getreent(), sig); } +#endif #if CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM IRAM_ATTR diff --git a/components/newlib/test_apps/.build-test-rules.yml b/components/newlib/test_apps/.build-test-rules.yml deleted file mode 100644 index 7e5c31fd38e..00000000000 --- a/components/newlib/test_apps/.build-test-rules.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps - -components/newlib/test_apps/newlib: - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: p4 rev3 migration # TODO: IDF-14415 diff --git a/components/newlib/test_apps/newlib/main/test_misaligned_access.c b/components/newlib/test_apps/newlib/main/test_misaligned_access.c new file mode 100644 index 00000000000..0ee1f0f7b3f --- /dev/null +++ b/components/newlib/test_apps/newlib/main/test_misaligned_access.c @@ -0,0 +1,162 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include "esp_heap_caps.h" +#include "soc/soc.h" +#include "hal/cpu_ll.h" +#include "unity.h" + +#define MAX_MEMTEST_SIZE 4096 + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" + +uint32_t test_function_dest_src_size(void (*foo)(...), bool pass_size) +{ + uint32_t ccount1, ccount2; + char* test_des = heap_caps_aligned_alloc(32, MAX_MEMTEST_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + char* test_src = heap_caps_aligned_alloc(32, MAX_MEMTEST_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + + TEST_ASSERT_NOT_NULL(test_des); + TEST_ASSERT_NOT_NULL(test_src); + + /* Prepare arrays for X-cmp functions to make the algorithm go through whole buffers. */ + memset(test_src, 'a', MAX_MEMTEST_SIZE); + test_src[MAX_MEMTEST_SIZE - 1] = 0; + memset(test_des, 'a', MAX_MEMTEST_SIZE); + test_des[MAX_MEMTEST_SIZE - 1] = 'b'; + test_des[MAX_MEMTEST_SIZE - 1] = 0; + + ccount1 = esp_cpu_get_cycle_count(); + if (pass_size) { + foo(test_des + 1, test_src + 2, MAX_MEMTEST_SIZE - 2); + } else { + foo(test_des + 1, test_src + 2); + } + ccount2 = esp_cpu_get_cycle_count(); + + heap_caps_free(test_des); + heap_caps_free(test_src); + + return ccount2 - ccount1; +} + +TEST_CASE("memcpy", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(memcpy, true); + /* esp32c2: 4128 cycles instead 28676. */ + TEST_ASSERT_LESS_THAN(10000, ccount); +} + +TEST_CASE("memcmp", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(memcmp, true); + /* esp32c2: 14259 cycles instead 49147. */ + TEST_ASSERT_LESS_THAN(20000, ccount); +} + +TEST_CASE("memmove", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(memmove, true); + /* esp32c2: 8086 cycles instead 33896. */ + TEST_ASSERT_LESS_THAN(15000, ccount); +} + +TEST_CASE("memmove - overlapping", "[misaligned_mem]") +{ + uint32_t ccount1, ccount2; + char* buf = heap_caps_aligned_alloc(32, MAX_MEMTEST_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + + TEST_ASSERT_NOT_NULL(buf); + + ccount1 = esp_cpu_get_cycle_count(); + memmove(buf + 5, buf + 2, MAX_MEMTEST_SIZE - 5); + ccount2 = esp_cpu_get_cycle_count(); + + heap_caps_free(buf); + + /* esp32c2: 11503 cycles instead 45024. */ + TEST_ASSERT_LESS_THAN(20000, ccount2 - ccount1); +} + +TEST_CASE("strcpy", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strcpy, false); + /* esp32c2: 17313 cycles instead 32771. */ + TEST_ASSERT_LESS_THAN(22000, ccount); +} + +TEST_CASE("strcmp", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strcmp, false); + /* esp32c2: 13191 cycles instead 32775. */ + TEST_ASSERT_LESS_THAN(20000, ccount); +} + +TEST_CASE("strncpy", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strncpy, true); + /* esp32c2: 21475 cycles instead 36859. */ + TEST_ASSERT_LESS_THAN(25000, ccount); +} + +TEST_CASE("strncmp", "[misaligned_mem]") +{ + uint32_t ccount = test_function_dest_src_size(strncmp, true); + /* esp32c2: 24369 cycles instead 49141. */ + TEST_ASSERT_LESS_THAN(30000, ccount); +} +#pragma GCC diagnostic pop // "-Wincompatible-pointer-types" "-Wstrict-prototypes" + +static bool fn_in_ram(void *fn) +{ + const int fnaddr = (int)fn; + return (fnaddr >= SOC_IRAM_LOW && fnaddr < SOC_IRAM_HIGH); +} + +TEST_CASE("mem functions in IRAM", "[misaligned_mem]") +{ + TEST_ASSERT_TRUE(fn_in_ram(memcpy)); + TEST_ASSERT_TRUE(fn_in_ram(memcmp)); + TEST_ASSERT_TRUE(fn_in_ram(memmove)); + TEST_ASSERT_TRUE(fn_in_ram(strcpy)); + TEST_ASSERT_TRUE(fn_in_ram(strncpy)); + TEST_ASSERT_TRUE(fn_in_ram(strcmp)); + TEST_ASSERT_TRUE(fn_in_ram(strncmp)); +} + +#if CONFIG_ESP_SYSTEM_MEMPROT_PMP +TEST_CASE("access across different PMP regions", "[misaligned_mem]") +{ + /* + * PMP configurations for load and store addresses may + * have different permissions (e.g., "R" vs. "RW"). + * + * Due to the timing alignment of internal signals, the address + * permission check may be incorrectly applied during the second + * part of a misaligned access transaction. + * + * As a workaround, insert two instructions (e.g. ADDI/NOP) between + * accessing to different memory regions. This spacing avoids the + * false permission check caused by signal timing overlap. + * + * This test may help identify the root issue in affected chips. + */ + + const void *src = (void *) SOC_DROM_MASK_LOW; + asm volatile("addi sp, sp, -16\n" + "lw t0, 2(%0)\n" +#if CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE + "nop\n" + "nop\n" +#endif + "sw t0, 3(sp)\n" + "addi sp, sp, 16" + :: "r"(src) : "memory"); +} +#endif diff --git a/components/newlib/test_apps/newlib/main/test_newlib.c b/components/newlib/test_apps/newlib/main/test_newlib.c index 8632e8a0948..f8e3a8f4680 100644 --- a/components/newlib/test_apps/newlib/main/test_newlib.c +++ b/components/newlib/test_apps/newlib/main/test_newlib.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/components/newlib/test_apps/no_rvfplib/CMakeLists.txt b/components/newlib/test_apps/no_rvfplib/CMakeLists.txt new file mode 100644 index 00000000000..798a42d024b --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) + +project(test_build) diff --git a/components/newlib/test_apps/no_rvfplib/README.md b/components/newlib/test_apps/no_rvfplib/README.md new file mode 100644 index 00000000000..ecf49aec4bb --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/README.md @@ -0,0 +1,6 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | + +This project tests building with the no_rvfplib configuration. + +This project uses MINIMAL_BUILD=y to reduce build time and dependencies. diff --git a/components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt b/components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt new file mode 100644 index 00000000000..1df31fac804 --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_main.c" + INCLUDE_DIRS ".") diff --git a/components/newlib/test_apps/no_rvfplib/main/test_main.c b/components/newlib/test_apps/no_rvfplib/main/test_main.c new file mode 100644 index 00000000000..b908720b326 --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/main/test_main.c @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +void app_main(void) +{ +} diff --git a/components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default b/components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default new file mode 100644 index 00000000000..09e782b75cf --- /dev/null +++ b/components/newlib/test_apps/no_rvfplib/sdkconfig.ci.default @@ -0,0 +1,2 @@ +CONFIG_IDF_TARGET="esp32c2" +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake index ad2c6b6bc41..a2273ed302c 100644 --- a/components/soc/project_include.cmake +++ b/components/soc/project_include.cmake @@ -13,11 +13,10 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) CONFIG_IDF_TARGET_ESP32C61 OR CONFIG_IDF_TARGET_ESP32H2 OR CONFIG_IDF_TARGET_ESP32H21) - set(_march "rv32imac_zicsr_zifencei_zaamo_zalrsc") - elseif(CONFIG_IDF_TARGET_ESP32H4) - set(_march "rv32imafcb_zicsr_zifencei_zaamo_zalrsc") - elseif(CONFIG_IDF_TARGET_ESP32P4) - set(_march "rv32imafc_zicsr_zifencei_zaamo_zalrsc") + set(_march "rv32imac_zicsr_zifencei") + elseif(CONFIG_IDF_TARGET_ESP32H4 OR + CONFIG_IDF_TARGET_ESP32P4) + set(_march "rv32imafc_zicsr_zifencei") elseif(NOT(CONFIG_IDF_TARGET_ESP32S2 OR CONFIG_IDF_TARGET_ESP32S3)) message(FATAL_ERROR "Unknown Espressif target: ${CONFIG_IDF_TARGET}") endif() @@ -48,19 +47,12 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) endif() endif() - if(CONFIG_SOC_CPU_HAS_DSP) - set(_march "${_march}_xespdsp") - endif() - # Set ABI and ARCH options if(CONFIG_SOC_CPU_HAS_FPU) idf_toolchain_add_flags(COMPILE_OPTIONS "-mabi=ilp32f") endif() idf_toolchain_add_flags(COMPILE_OPTIONS "-march=${_march}") - if(NOT CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE) - idf_toolchain_add_flags(COMPILE_OPTIONS "-mtune=esp-base") - endif() idf_toolchain_rerun_abi_detection() else() message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}") From 988d0da6d4def9772fc5447a2ee3999dbe60ab74 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Fri, 12 Dec 2025 11:07:30 +0700 Subject: [PATCH 14/18] fix(esp_rom): adapt changes --- components/esp_rom/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 8faf53431af..b120d67bf74 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -147,6 +147,10 @@ if(ESP_TEE_BUILD) if(CONFIG_LIBC_NEWLIB AND CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT) rom_linker_script("newlib-nano") endif() + rom_linker_script("libc") + if(CONFIG_ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY) + rom_linker_script("libc-suboptimal_for_misaligned_mem") + endif() endif() if(BOOTLOADER_BUILD) @@ -171,8 +175,8 @@ if(BOOTLOADER_BUILD) else() rom_linker_script("libc") endif() - if(CONFIG_ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY - AND NOT CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS) + if(CONFIG_ESP_ROM_HAS_SUBOPTIMAL_NEWLIB_ON_MISALIGNED_MEMORY) + # For bootloader use only ROM functions due to 'relocation truncated to fit' error rom_linker_script("libc-suboptimal_for_misaligned_mem") endif() if(CONFIG_LIBC_NEWLIB) From f9ad9a4d16a5aba0309b37efc4f9e47eacf516cc Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Tue, 16 Dec 2025 11:35:47 +0700 Subject: [PATCH 15/18] fix(esp_rom): use hmac_md5 and hmac_md5_vector from ROM only if CONFIG_LIBC_NEWLIB --- components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld | 2 ++ components/esp_rom/esp32/ld/esp32.rom.redefined.ld | 2 -- components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 2 -- components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld | 2 ++ components/esp_rom/esp32s2/ld/esp32s2.rom.ld | 2 -- components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld | 2 ++ components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 2 -- components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld | 2 ++ 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld b/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld index aa4f48f359b..56c55188ae0 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld @@ -72,3 +72,5 @@ strcoll = 0x40001398; strlwr = 0x40001524; strncasecmp = 0x40001550; strupr = 0x4000174c; +PROVIDE ( hmac_md5 = 0x4005d264 ); +PROVIDE ( hmac_md5_vector = 0x4005d17c ); diff --git a/components/esp_rom/esp32/ld/esp32.rom.redefined.ld b/components/esp_rom/esp32/ld/esp32.rom.redefined.ld index a7f62b86761..6cc166ed66b 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.redefined.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.redefined.ld @@ -19,8 +19,6 @@ PROVIDE ( ets_timer_done = 0x40008428 ); PROVIDE ( ets_timer_init = 0x400084e8 ); PROVIDE ( ets_timer_handler_isr = 0x40008454 ); PROVIDE ( ets_timer_setfn = 0x40008350 ); -PROVIDE ( hmac_md5 = 0x4005d264 ); -PROVIDE ( hmac_md5_vector = 0x4005d17c ); PROVIDE ( hmac_sha1 = 0x40060acc ); PROVIDE ( hmac_sha1_vector = 0x400609e4 ); PROVIDE ( hmac_sha256 = 0x40060d58 ); diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index d5c11903c5e..133dca5af56 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -410,8 +410,6 @@ md5_vector = 0x40000610; MD5Init = 0x40000614; MD5Update = 0x40000618; MD5Final = 0x4000061c; -hmac_md5_vector = 0x40000620; -hmac_md5 = 0x40000624; crc32_le = 0x40000628; crc32_be = 0x4000062c; crc16_le = 0x40000630; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld index 2f3662e60c9..40c5529153f 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld @@ -48,3 +48,5 @@ strcoll = 0x400003e8; strlwr = 0x400003f4; strncasecmp = 0x400003f8; strupr = 0x40000418; +hmac_md5_vector = 0x40000620; +hmac_md5 = 0x40000624; diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.ld index 2256bc2b321..dcc28eb645a 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.ld @@ -359,8 +359,6 @@ PROVIDE ( gpio_pin_wakeup_disable = 0x40019404 ); PROVIDE ( gpio_pin_wakeup_enable = 0x400193c8 ); PROVIDE ( g_shared_buffers = 0x3ffeab04 ); PROVIDE ( g_ticks_per_us = 0x3ffffd70 ); -PROVIDE ( hmac_md5 = 0x40005490 ); -PROVIDE ( hmac_md5_vector = 0x400053a0 ); PROVIDE ( ibus_baseaddrs = 0x3ffaf03c ); PROVIDE ( intr_matrix_set = 0x4000f1d0 ); PROVIDE ( _iram0_text_end = 0x40000540 ); diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld index dc4ef563ab6..c75f24e48e0 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld @@ -62,3 +62,5 @@ strcoll = 0x40007ce8; strlwr = 0x40007e68; strncasecmp = 0x40007e94; strupr = 0x40008084; +PROVIDE ( hmac_md5 = 0x40005490 ); +PROVIDE ( hmac_md5_vector = 0x400053a0 ); diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 63b0f8464ad..29efd9036fd 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -518,8 +518,6 @@ md5_vector = 0x40001c50; MD5Init = 0x40001c5c; MD5Update = 0x40001c68; MD5Final = 0x40001c74; -hmac_md5_vector = 0x40001c80; -hmac_md5 = 0x40001c8c; crc32_le = 0x40001c98; crc32_be = 0x40001ca4; crc16_le = 0x40001cb0; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld index f964e305f8a..ccdf4c0f741 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld @@ -42,3 +42,5 @@ strcoll = 0x400013a4; strlwr = 0x400013c8; strncasecmp = 0x400013d4; strupr = 0x40001434; +hmac_md5_vector = 0x40001c80; +hmac_md5 = 0x40001c8c; From 18b369cc9db7318311d0888c8684818b03658e0d Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Mon, 15 Dec 2025 18:44:10 +0700 Subject: [PATCH 16/18] fix(esp_libc): add workaround for pthread_sigmask declaration in picolibc signal.h --- components/newlib/platform_include/signal.h | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 components/newlib/platform_include/signal.h diff --git a/components/newlib/platform_include/signal.h b/components/newlib/platform_include/signal.h new file mode 100644 index 00000000000..c5364551f0c --- /dev/null +++ b/components/newlib/platform_include/signal.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "sdkconfig.h" + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +/* TODO GCC-441: remove this file */ +#if CONFIG_LIBC_PICOLIBC +#if __POSIX_VISIBLE >= 199506 +int pthread_sigmask(int, const sigset_t *, sigset_t *); +#endif +#endif + +#ifdef __cplusplus +} +#endif From 776f9fd09d9c3d939c3a8cf9211dce9670abb489 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Fri, 30 Jan 2026 13:59:08 +0700 Subject: [PATCH 17/18] fix(newlib): fix ci: add .build-test-rules.yml --- components/newlib/test_apps/.build-test-rules.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 components/newlib/test_apps/.build-test-rules.yml diff --git a/components/newlib/test_apps/.build-test-rules.yml b/components/newlib/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..5f9e3344455 --- /dev/null +++ b/components/newlib/test_apps/.build-test-rules.yml @@ -0,0 +1,5 @@ +components/newlib/test_apps/newlib: + disable_test: + - if: IDF_TARGET in ["esp32h21", "esp32h4", "esp32p4"] + temporary: true + reason: p4 rev3 migration # TODO IDF-14415 From 74ed018fc18288309561e7ac981979a6cb483a7e Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Mon, 10 Nov 2025 20:44:55 +0700 Subject: [PATCH 18/18] fix(test): fix tests according to the new toolchain flags --- .../main/import_lib_example_main.cpp | 4 +- tools/test_build_system/test_cmake.py | 75 +++++++++++++------ 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp b/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp index 0e9ecb3ba46..069296cb03f 100644 --- a/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp +++ b/examples/build_system/cmake/import_lib/main/import_lib_example_main.cpp @@ -7,7 +7,6 @@ #include "esp_log.h" #include "esp_vfs_fat.h" #include "tinyxml2.h" -#include "sdkconfig.h" // TODO IDF-11323: remove static const char *TAG = "example"; @@ -30,12 +29,11 @@ extern "C" void app_main(void) tinyxml2::XMLDocument data; data.LoadFile("/spiflash/sample.xml"); -#if !CONFIG_LIBC_PICOLIBC // TODO IDF-11323: subproject builds with default toolchain-esp*.cmake. No additional -specs=picolibc.specs applied tinyxml2::XMLPrinter printer; data.Print(&printer); ESP_LOGI(TAG, "Read XML data:\n%s", printer.CStr()); -#endif + const char* to_data = data.FirstChildElement("note")->FirstChildElement("to")->GetText(); const char* from_data = data.FirstChildElement("note")->FirstChildElement("from")->GetText(); const char* heading_data = data.FirstChildElement("note")->FirstChildElement("heading")->GetText(); diff --git a/tools/test_build_system/test_cmake.py b/tools/test_build_system/test_cmake.py index 4464a3d12e9..1b944b7f5cf 100644 --- a/tools/test_build_system/test_cmake.py +++ b/tools/test_build_system/test_cmake.py @@ -1,5 +1,6 @@ -# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 +import json import logging import os import re @@ -48,28 +49,60 @@ def test_build_custom_cmake_project_host() -> None: run_cmake_and_build(str(idf_path / 'examples' / 'build_system' / 'cmake' / 'idf_as_lib'), '-G', 'Ninja') -def test_build_cmake_library_psram_workaround(test_app_copy: Path) -> None: +def test_build_cmake_library_with_toolchain_flags(test_app_copy: Path) -> None: + logging.info('Building a project with CMake library imported with modified toolchain flags') + idf_path = Path(os.environ['IDF_PATH']) + + import_lib_path = idf_path / 'examples' / 'build_system' / 'cmake' / 'import_lib' + run_cmake_and_build( + str(import_lib_path), + '-G', + 'Ninja', + f'-DSDKCONFIG_DEFAULTS={import_lib_path / "sdkconfig.defaults"}', + ) + + +def check_flag_in_compile_commands(build_dir: Path, flag_to_find: str) -> None: + with open(build_dir / 'build' / 'compile_commands.json', encoding='utf-8') as f: + compile_commands = json.load(f) + # check if compile_commands is an array + if not isinstance(compile_commands, list): + assert False, f'compile_commands is not a list: {compile_commands}' + assert len(compile_commands) != 0, 'compile_commands is empty' + for entry in compile_commands: + command = entry['command'] + assert isinstance(command, str), f'command is not a string: {command}' + flag_is_found = flag_to_find in command + if flag_is_found: + continue # Flag found in command, no need to check response files + # check if command contains response file paths starts with @ + response_file_paths = re.findall(r'@([^\s]+)', command) + for response_file_path in response_file_paths: + # check if the flag file contains flag_to_find + try: + # Strip surrounding quotes and normalize the path + response_file_path = response_file_path.strip('"\'\\') + response_file_path = Path(response_file_path).resolve() + with open(response_file_path, encoding='utf-8') as f: + flags = f.read() + if flag_to_find in flags: + flag_is_found = True + break + except FileNotFoundError: + assert False, f'{response_file_path} does not exist' + if not flag_is_found: + assert False, f'{flag_to_find} not found in {command}' + + +def test_build_cmake_library_psram_workaround(idf_py: IdfPyFunc, test_app_copy: Path) -> None: logging.info( 'Building a project with CMake library imported and PSRAM workaround, all files compile with workaround' ) - idf_path = Path(os.environ['IDF_PATH']) (test_app_copy / 'sdkconfig.defaults').write_text( '\n'.join(['CONFIG_SPIRAM=y', 'CONFIG_SPIRAM_CACHE_WORKAROUND=y']) ) - run_cmake( - '-G', - 'Ninja', - '-DCOMPONENTS=main;esp_psram', - '-DSDKCONFIG_DEFAULTS={}'.format(test_app_copy / 'sdkconfig.defaults'), - str(idf_path / 'examples' / 'build_system' / 'cmake' / 'import_lib'), - ) - with open((test_app_copy / 'build' / 'compile_commands.json'), 'r', encoding='utf-8') as f: - data = f.read() - res = re.findall(r'.*\"command\".*', data) - for r in res: - assert 'mfix-esp32-psram-cache-issue' in r, ( - 'All commands in compile_commands.json should use PSRAM cache workaround' - ) + idf_py('reconfigure') + check_flag_in_compile_commands(test_app_copy, '-mfix-esp32-psram-cache-issue') def test_build_cmake_library_psram_strategies(idf_py: IdfPyFunc, test_app_copy: Path) -> None: @@ -85,13 +118,7 @@ def test_build_cmake_library_psram_strategies(idf_py: IdfPyFunc, test_app_copy: ) ) idf_py('reconfigure') - with open((test_app_copy / 'build' / 'compile_commands.json'), 'r', encoding='utf-8') as f: - data = f.read() - res = re.findall(r'.*\"command\".*', data) - for r in res: - assert f'mfix-esp32-psram-cache-strategy={strategy.lower()}' in r, ( - 'All commands in compile_commands.json should use PSRAM cache workaround strategy' - ) + check_flag_in_compile_commands(test_app_copy, f'-mfix-esp32-psram-cache-strategy={strategy.lower()}') (test_app_copy / 'sdkconfig').unlink()