diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index cae47752a7c..4ccb6386a47 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -25,18 +25,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/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/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 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" 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); 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_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_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 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/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index e2c1801928b..b120d67bf74 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -144,9 +144,13 @@ 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() + 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) 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..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 @@ -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,18 @@ __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; +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/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.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.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..40c5529153f 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,18 @@ 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; +hmac_md5_vector = 0x40000620; +hmac_md5 = 0x40000624; 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/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/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.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.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..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 @@ -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,17 @@ __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; +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.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..ccdf4c0f741 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,18 @@ 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; +hmac_md5_vector = 0x40001c80; +hmac_md5 = 0x40001c8c; 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/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/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/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/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 1f88a944230..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() @@ -63,24 +64,35 @@ 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") +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 @@ -94,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") @@ -117,8 +140,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/Kconfig b/components/newlib/Kconfig index 9a30784c218..2b333eebedb 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. @@ -145,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 @@ -160,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/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 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/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/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/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/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/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/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/project_include.cmake b/components/newlib/project_include.cmake index 62922378469..193f166f2c2 100644 --- a/components/newlib/project_include.cmake +++ b/components/newlib/project_include.cmake @@ -1,3 +1,25 @@ -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() + + 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) + endif() endif() diff --git a/components/newlib/sbom.yml b/components/newlib/sbom.yml index 496cb10c30b..a269a621e0e 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/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/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/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/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/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 2e0fc30f148..c623a815a28 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 */ @@ -13,9 +13,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include "esp_newlib.h" @@ -33,21 +34,59 @@ 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 +#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, @@ -143,20 +182,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 +195,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/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 0a15125fc34..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; @@ -105,6 +106,11 @@ 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) @@ -117,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 @@ -124,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 index 7e5c31fd38e..5f9e3344455 100644 --- a/components/newlib/test_apps/.build-test-rules.yml +++ b/components/newlib/test_apps/.build-test-rules.yml @@ -1,7 +1,5 @@ -# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps - components/newlib/test_apps/newlib: disable_test: - - if: IDF_TARGET == "esp32p4" + - if: IDF_TARGET in ["esp32h21", "esp32h4", "esp32p4"] temporary: true - reason: p4 rev3 migration # TODO: IDF-14415 + 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/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/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/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 new file mode 100644 index 00000000000..a2273ed302c --- /dev/null +++ b/components/soc/project_include.cmake @@ -0,0 +1,60 @@ +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") + 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() + + # 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_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") + endif() + 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}") + + idf_toolchain_rerun_abi_detection() + else() + message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}") + endif() +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/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/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'), 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/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)) 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): 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/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() diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index b1064cacae0..79156d4dcc4 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -895,13 +895,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..cd273040fdb --- /dev/null +++ b/tools/cmake/toolchain_flags.cmake @@ -0,0 +1,182 @@ +# 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() + +# 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" 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() 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" } } ]