diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index 453e167784..78fd2f3b9d 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -25,19 +25,33 @@ 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- - - IDF_TARGET=esp32s31 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 \ + esp32s31" + 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 c6c4fb23ff..4669a8f333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,11 +78,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 47eb0a5e8e..b9a68225d6 100644 --- a/Kconfig +++ b/Kconfig @@ -794,7 +794,6 @@ 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 - CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION - CONFIG_I3C_MASTER_ENABLED - CONFIG_ESPTOOLPY_FAST_REFLASHING diff --git a/components/bt/common/osi/include/osi/pkt_queue.h b/components/bt/common/osi/include/osi/pkt_queue.h index 96277c3e18..38eff71ffa 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 1027c9a293..5e8495d31a 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 a8ce979281..7f63fd4f75 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" "split_argv.c" @@ -43,6 +46,14 @@ idf_component_register(SRCS ${srcs} esp_usb_cdc_rom_console ) +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 b8c304d1b9..bedcf3549f 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. */ @@ -172,6 +184,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); @@ -180,6 +202,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, @@ -231,6 +254,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 912fa90a66..96132fa984 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 4e051cf6a8..64fcf23a12 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 cbcca4d448..2e326fcb93 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 0000000000..f7f4d46b17 --- /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 b253135b6c..0039ab47ae 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 2336f50da5..c475fd72d1 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 23c591ae01..5aaf766ed9 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 @@ -152,7 +155,7 @@ static esp_console_cmd_t s_quit_cmd = { ran separately in test_console_repl */ TEST_CASE("esp console repl test", "[console][ignore]") { - set_leak_threshold(416); + set_leak_threshold(248); s_test_console_mutex = xSemaphoreCreateMutexStatic(&s_test_console_mutex_buf); TEST_ASSERT_NOT_NULL(s_test_console_mutex); @@ -189,7 +192,7 @@ TEST_CASE("esp console repl test", "[console][ignore]") TEST_CASE("esp console repl deinit", "[console][ignore]") { - set_leak_threshold(416); + set_leak_threshold(248); 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(); @@ -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/console/test_apps/console/pytest_console.py b/components/console/test_apps/console/pytest_console.py index df7901ff36..45ffbd5441 100644 --- a/components/console/test_apps/console/pytest_console.py +++ b/components/console/test_apps/console/pytest_console.py @@ -19,7 +19,7 @@ def do_test_repl_deinit(dut: Dut) -> None: def do_test_help_generic(dut: Dut, registration_order: str) -> None: dut.expect_exact('Press ENTER to see the list of tests') - dut.confirm_write('"esp console help command - {} registration"'.format(registration_order), expect_str='esp>') + dut.confirm_write(f'"esp console help command - {registration_order} registration"', expect_str='esp>') dut.confirm_write('help', expect_str='aaa') @@ -269,3 +269,21 @@ def test_console_help_re_register(dut: Dut, test_on: str) -> None: dut.expect_exact('should appear last in help') dut.expect_exact('should appear first in help') + + +@idf_parametrize('config', ['defaults'], indirect=['config']) +@idf_parametrize( + 'target,test_on,markers', + [ + ('esp32', 'target', (pytest.mark.generic,)), + ('esp32c3', 'target', (pytest.mark.generic,)), + ('esp32', 'qemu', (pytest.mark.host_test, pytest.mark.qemu)), + ], + indirect=['target'], +) +def test_console_custom_uart_repl(dut: Dut, test_on: str) -> None: + dut.expect_exact('Press ENTER to see the list of tests') + dut.confirm_write('"esp console repl custom_uart test"', expect_str='Running repl on UART1') + + # make sure that global stdout has not been changed + dut.expect_exact('ByeBye') diff --git a/components/cxx/cxx_init.cpp b/components/cxx/cxx_init.cpp index bfff600583..dcd6126971 100644 --- a/components/cxx/cxx_init.cpp +++ b/components/cxx/cxx_init.cpp @@ -29,6 +29,11 @@ extern "C" size_t __cxx_eh_arena_size_get(void) #endif } +extern "C" void __esp_idf_pthread_rwlock_lazy_allocation(void) +{ + /* TODO IDF-14862: remove */ +} + /** * Dummy function used to force linking this file. * This works via -u __cxx_init_dummy flag in CMakeLists.txt diff --git a/components/cxx/test_apps/general/main/test_cxx_general.cpp b/components/cxx/test_apps/general/main/test_cxx_general.cpp index 8828157436..0bb43803a0 100644 --- a/components/cxx/test_apps/general/main/test_cxx_general.cpp +++ b/components/cxx/test_apps/general/main/test_cxx_general.cpp @@ -15,6 +15,7 @@ #include "unity_test_utils.h" #include "soc/soc.h" #include +#include #include #include "esp_timer.h" @@ -343,6 +344,25 @@ TEST_CASE("test std::this_thread::sleep_for basic functionality", "[misc]") TEST_ASSERT_GREATER_OR_EQUAL(long_sleep.count(), elapsed_us); } +TEST_CASE("test std::shared_mutex memory leaks", "[misc]") +{ + /* TODO IDF-14862: + * check if PTHREAD_RWLOCK_INITIALIZER is still defined to not break user's code + */ + pthread_rwlock_t m = PTHREAD_RWLOCK_INITIALIZER; + TEST_ASSERT_NOT_EQUAL_UINT(NULL, m); + + std::shared_mutex* mutex_not_initialized = new std::shared_mutex(); + delete mutex_not_initialized; + + /* A locked mutex can't be destroyed, don't test it here */ + + std::shared_mutex* mutex_unlocked = new std::shared_mutex(); + mutex_unlocked->lock(); + mutex_unlocked->unlock(); + delete mutex_unlocked; +} + extern "C" void app_main(void) { s_testTLS.foo(); /* allocates memory that will be reused */ diff --git a/components/esp_coex/include/private/esp_modem_wrapper.h b/components/esp_coex/include/private/esp_modem_wrapper.h index 8ce7a3a433..8ea0551532 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/include/esp_cpu.h b/components/esp_hw_support/include/esp_cpu.h index 87678f2f6c..c62b0c84d7 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_libc/CMakeLists.txt b/components/esp_libc/CMakeLists.txt index 02a03423b5..1234576f4e 100644 --- a/components/esp_libc/CMakeLists.txt +++ b/components/esp_libc/CMakeLists.txt @@ -64,7 +64,11 @@ else() list(APPEND srcs "src/picolibc/picolibc_init.c" "src/picolibc/rand.c" - "src/picolibc/open_memstream.c") + "src/picolibc/open_memstream.c" + "src/picolibc/errno.c") + if(CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY) + list(APPEND srcs "src/picolibc/getreent.c") + endif() endif() set(ldfragments "") diff --git a/components/esp_libc/Kconfig b/components/esp_libc/Kconfig index 3fa79f1e6b..6c7447c9d6 100644 --- a/components/esp_libc/Kconfig +++ b/components/esp_libc/Kconfig @@ -2,15 +2,46 @@ menu "LibC" choice LIBC prompt "LibC to build application with" - default LIBC_NEWLIB + default LIBC_NEWLIB if IDF_TOOLCHAIN_CLANG + default LIBC_PICOLIBC 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 +49,6 @@ menu "LibC" config LIBC_LOCKS_PLACE_IN_IRAM bool "Place lock API in IRAM" default y - depends on LIBC_NEWLIB help Enable this option to include be able to call the lock API from code that runs while cache is disabled, e.g. IRAM interrupts. diff --git a/components/esp_libc/platform_include/stdio.h b/components/esp_libc/platform_include/stdio.h index 282bc2319c..2322f9a8dd 100644 --- a/components/esp_libc/platform_include/stdio.h +++ b/components/esp_libc/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/esp_libc/platform_include/stdio_ext.h b/components/esp_libc/platform_include/stdio_ext.h index 8c49947ff3..0ac12ebe12 100644 --- a/components/esp_libc/platform_include/stdio_ext.h +++ b/components/esp_libc/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/esp_libc/platform_include/sys/cdefs.h b/components/esp_libc/platform_include/sys/cdefs.h new file mode 100644 index 0000000000..d87dbd85aa --- /dev/null +++ b/components/esp_libc/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/esp_libc/platform_include/sys/fcntl.h b/components/esp_libc/platform_include/sys/fcntl.h new file mode 100644 index 0000000000..93c9cb458c --- /dev/null +++ b/components/esp_libc/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/esp_libc/platform_include/sys/time.h b/components/esp_libc/platform_include/sys/time.h index 7901acca33..88ca7867aa 100644 --- a/components/esp_libc/platform_include/sys/time.h +++ b/components/esp_libc/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/esp_libc/platform_include/sys/unistd.h b/components/esp_libc/platform_include/sys/unistd.h index 483fd3cca8..d6b152f7b1 100644 --- a/components/esp_libc/platform_include/sys/unistd.h +++ b/components/esp_libc/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/esp_libc/project_include.cmake b/components/esp_libc/project_include.cmake index e365170283..193f166f2c 100644 --- a/components/esp_libc/project_include.cmake +++ b/components/esp_libc/project_include.cmake @@ -16,6 +16,8 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) else() idf_toolchain_remove_flags(LINK_OPTIONS "--specs=nano.specs") endif() + + idf_toolchain_rerun_abi_detection() else() # TODO IDF-14338 if(CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND) idf_build_set_property(COMPILE_OPTIONS "-mdisable-hardware-atomics" APPEND) diff --git a/components/esp_libc/sbom.yml b/components/esp_libc/sbom.yml index fec4fa1104..a269a621e0 100644 --- a/components/esp_libc/sbom.yml +++ b/components/esp_libc/sbom.yml @@ -1,9 +1,7 @@ -name: 'newlib' -version: '4.5.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/esp_libc/sbom_newlibc.yml b/components/esp_libc/sbom_newlibc.yml new file mode 100644 index 0000000000..5fdb0f72bf --- /dev/null +++ b/components/esp_libc/sbom_newlibc.yml @@ -0,0 +1,10 @@ +if: 'LIBC_NEWLIB' +name: 'newlib' +version: '4.5.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/esp_libc/sbom_picolibc.yml b/components/esp_libc/sbom_picolibc.yml new file mode 100644 index 0000000000..4056cc4221 --- /dev/null +++ b/components/esp_libc/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/esp_libc/src/locks.c b/components/esp_libc/src/locks.c index 582256dc3d..580f7b0e7e 100644 --- a/components/esp_libc/src/locks.c +++ b/components/esp_libc/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/esp_libc/src/picolibc/errno.c b/components/esp_libc/src/picolibc/errno.c new file mode 100644 index 0000000000..67479c0ed7 --- /dev/null +++ b/components/esp_libc/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/esp_libc/src/picolibc/getreent.c b/components/esp_libc/src/picolibc/getreent.c new file mode 100644 index 0000000000..b494d52ee5 --- /dev/null +++ b/components/esp_libc/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/esp_libc/src/picolibc/picolibc_init.c b/components/esp_libc/src/picolibc/picolibc_init.c index efe982e897..2d7f6c6855 100644 --- a/components/esp_libc/src/picolibc/picolibc_init.c +++ b/components/esp_libc/src/picolibc/picolibc_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,21 +33,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 +181,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 +194,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/esp_libc/src/syscalls.c b/components/esp_libc/src/syscalls.c index 23dfd834b4..96a743017d 100644 --- a/components/esp_libc/src/syscalls.c +++ b/components/esp_libc/src/syscalls.c @@ -110,6 +110,10 @@ int fcntl(int fd, int cmd, ...) return _fcntl_r(__getreent(), fd, cmd, arg); } +int getpid() +{ + return _getpid_r(__getreent()); +} #endif // CONFIG_LIBC_PICOLIBC void _exit(int __status) diff --git a/components/esp_phy/CMakeLists.txt b/components/esp_phy/CMakeLists.txt index 44c9d4d156..1cbf65bdf9 100644 --- a/components/esp_phy/CMakeLists.txt +++ b/components/esp_phy/CMakeLists.txt @@ -162,7 +162,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 ${esp_libc_dir}/platform_include diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 593bc1de4f..8246bbd351 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -145,7 +145,7 @@ endif() if(ESP_TEE_BUILD) rom_linker_script("heap") - if(CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT) + if(CONFIG_LIBC_NEWLIB AND CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT) rom_linker_script("newlib-nano") endif() rom_linker_script("libc") 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 506c0f7753..662c7a0db5 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 49c49b19b2..aa4f48f359 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.newlib-reent-funcs.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -59,3 +59,16 @@ __sinit_lock_release = 0x40001e2c; __env_lock = 0x40001fd4; __env_unlock = 0x40001fe0; _getenv_r = 0x40001fbc; +tolower = 0x40001868; +toupper = 0x40001884; +isalnum = 0x40000f04; +isalpha = 0x40000f18; +isdigit = 0x40000f64; +islower = 0x40000f78; +isspace = 0x40000fd4; +isupper = 0x40000fe8; +strcasecmp = 0x400011cc; +strcoll = 0x40001398; +strlwr = 0x40001524; +strncasecmp = 0x40001550; +strupr = 0x4000174c; diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.libc.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.libc.ld index 920da09982..7d90b649ce 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 a6963f86d0..f9eda11b4a 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,3 +63,16 @@ puts = 0x4000065c; putc = 0x40000660; putchar = 0x40000664; __errno = 0x40000670; +toupper = 0x400004ec; +tolower = 0x400004f0; +isalnum = 0x400004bc; +isalpha = 0x400004c0; +isdigit = 0x400004d0; +islower = 0x400004d4; +isspace = 0x400004e4; +isupper = 0x400004e8; +strcasecmp = 0x40000504; +strcoll = 0x4000051c; +strlwr = 0x40000528; +strncasecmp = 0x4000052c; +strupr = 0x4000054c; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.libc.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.libc.ld index a7476cac1d..f206243491 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 69e93fccd9..2f3662e60c 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,3 +35,16 @@ PROVIDE( _fwalk = 0x40000464 ); PROVIDE( _fwalk_reent = 0x40000468 ); PROVIDE( __swbuf_r = 0x40000474 ); __swbuf = 0x40000478; +toupper = 0x400003b8; +tolower = 0x400003bc; +isalnum = 0x40000388; +isalpha = 0x4000038c; +isdigit = 0x4000039c; +islower = 0x400003a0; +isspace = 0x400003b0; +isupper = 0x400003b4; +strcasecmp = 0x400003d0; +strcoll = 0x400003e8; +strlwr = 0x400003f4; +strncasecmp = 0x400003f8; +strupr = 0x40000418; diff --git a/components/esp_rom/esp32c5/ld/esp32c5.rom.libc.ld b/components/esp_rom/esp32c5/ld/esp32c5.rom.libc.ld index a7b1e8b03c..ecdbff4f3a 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 0a970172a7..24806f1995 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 16c5b60710..4f3356731f 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 2bae479247..454a1779ab 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 771fa2f084..676cfcdf2c 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 0e6df59a28..80a4717173 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 d6680a5d7f..2ad368242c 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 770211f2c3..2392259836 100644 --- a/components/esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld +++ b/components/esp_rom/esp32h2/ld/esp32h2.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,3 +39,16 @@ __swhatbuf_r = 0x400005bc; __swbuf_r = 0x400005c0; __swbuf = 0x400005c4; __swsetup_r = 0x400005c8; +toupper = 0x40000504; +tolower = 0x40000508; +isalnum = 0x400004d4; +isalpha = 0x400004d8; +isdigit = 0x400004e8; +islower = 0x400004ec; +isspace = 0x400004fc; +isupper = 0x40000500; +strcasecmp = 0x4000051c; +strcoll = 0x40000534; +strlwr = 0x40000540; +strncasecmp = 0x40000544; +strupr = 0x40000564; diff --git a/components/esp_rom/esp32h21/ld/esp32h21.rom.libc.ld b/components/esp_rom/esp32h21/ld/esp32h21.rom.libc.ld index 18a91402e1..830b2e454a 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 1f79078a48..0d1ca97329 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/esp32h4/ld/esp32h4.rom.libc.ld b/components/esp_rom/esp32h4/ld/esp32h4.rom.libc.ld index 3da63696fc..379545b003 100644 --- a/components/esp_rom/esp32h4/ld/esp32h4.rom.libc.ld +++ b/components/esp_rom/esp32h4/ld/esp32h4.rom.libc.ld @@ -31,41 +31,28 @@ strlen = 0x400004b8; strstr = 0x400004bc; bzero = 0x400004c0; sbrk = 0x400004c4; -isalnum = 0x400004c8; -isalpha = 0x400004cc; isascii = 0x400004d0; isblank = 0x400004d4; iscntrl = 0x400004d8; -isdigit = 0x400004dc; -islower = 0x400004e0; isgraph = 0x400004e4; isprint = 0x400004e8; ispunct = 0x400004ec; -isspace = 0x400004f0; -isupper = 0x400004f4; -toupper = 0x400004f8; -tolower = 0x400004fc; toascii = 0x40000500; memccpy = 0x40000504; memchr = 0x40000508; memrchr = 0x4000050c; -strcasecmp = 0x40000510; strcasestr = 0x40000514; strcat = 0x40000518; strchr = 0x4000051c; strcspn = 0x40000520; -strcoll = 0x40000524; strlcat = 0x40000528; strlcpy = 0x4000052c; -strlwr = 0x40000530; -strncasecmp = 0x40000534; strncat = 0x40000538; strnlen = 0x4000053c; strrchr = 0x40000540; strsep = 0x40000544; strspn = 0x40000548; strtok_r = 0x4000054c; -strupr = 0x40000550; longjmp = 0x40000554; setjmp = 0x40000558; abs = 0x4000055c; diff --git a/components/esp_rom/esp32h4/ld/esp32h4.rom.newlib.ld b/components/esp_rom/esp32h4/ld/esp32h4.rom.newlib.ld index 381add3063..660fcc406f 100644 --- a/components/esp_rom/esp32h4/ld/esp32h4.rom.newlib.ld +++ b/components/esp_rom/esp32h4/ld/esp32h4.rom.newlib.ld @@ -37,3 +37,16 @@ __swhatbuf_r = 0x40000484; __swbuf_r = 0x40000488; __swbuf = 0x4000048c; __swsetup_r = 0x40000490; +toupper = 0x400004f8; +tolower = 0x400004fc; +isalnum = 0x400004c8; +isalpha = 0x400004cc; +isdigit = 0x400004dc; +islower = 0x400004e0; +isspace = 0x400004f0; +isupper = 0x400004f4; +strcasecmp = 0x40000510; +strcoll = 0x40000524; +strlwr = 0x40000530; +strncasecmp = 0x40000534; +strupr = 0x40000550; diff --git a/components/esp_rom/esp32p4/ld/esp32p4.rom.libc.ld b/components/esp_rom/esp32p4/ld/esp32p4.rom.libc.ld index 65d90e205f..f38b60c22f 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 2929b424ff..369d1c01fe 100644 --- a/components/esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld +++ b/components/esp_rom/esp32p4/ld/esp32p4.rom.newlib.ld @@ -39,3 +39,16 @@ __swhatbuf_r = 0x4fc00384; __swbuf_r = 0x4fc00388; __swbuf = 0x4fc0038c; __swsetup_r = 0x4fc00390; +toupper = 0x4fc002cc; +tolower = 0x4fc002d0; +isalnum = 0x4fc0029c; +isalpha = 0x4fc002a0; +isdigit = 0x4fc002b0; +islower = 0x4fc002b4; +isspace = 0x4fc002c4; +isupper = 0x4fc002c8; +strcasecmp = 0x4fc002e4; +strcoll = 0x4fc002fc; +strlwr = 0x4fc00308; +strncasecmp = 0x4fc0030c; +strupr = 0x4fc0032c; diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.libc-funcs.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.libc-funcs.ld index ae5bc633bf..863508a4f0 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 4b8aa9c26c..dc4ef563ab 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-reent-funcs.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -50,3 +50,15 @@ __locale_ctype_ptr_l = 0x40001c24; __locale_mb_cur_max = 0x40001c0c; strcasecmp = 0x40007b38; strcasestr = 0x40007b7c; +tolower = 0x40008158; +toupper = 0x40008174; +isalnum = 0x400078d8; +isalpha = 0x400078e8; +isdigit = 0x40007930; +islower = 0x40007948; +isspace = 0x400079ac; +isupper = 0x400079c4; +strcoll = 0x40007ce8; +strlwr = 0x40007e68; +strncasecmp = 0x40007e94; +strupr = 0x40008084; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.libc.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.libc.ld index cf3f350174..73a3ac5e83 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 b0957aac2a..f964e305f8 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.newlib.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,3 +29,16 @@ PROVIDE( _fwalk = 0x40001518 ); PROVIDE( _fwalk_reent = 0x40001524 ); PROVIDE( __swbuf_r = 0x40001548 ); __swbuf = 0x40001554; +toupper = 0x40001314; +tolower = 0x40001320; +isalnum = 0x40001284; +isalpha = 0x40001290; +isdigit = 0x400012c0; +islower = 0x400012cc; +isspace = 0x400012fc; +isupper = 0x40001308; +strcasecmp = 0x4000135c; +strcoll = 0x400013a4; +strlwr = 0x400013c8; +strncasecmp = 0x400013d4; +strupr = 0x40001434; diff --git a/components/esp_system/ld/elf_misc.ld.in b/components/esp_system/ld/elf_misc.ld.in index 74ce86bf03..be87bf97b7 100644 --- a/components/esp_system/ld/elf_misc.ld.in +++ b/components/esp_system/ld/elf_misc.ld.in @@ -69,7 +69,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 26966a5003..d7f6bc095b 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -395,12 +395,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors.*))) KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors)) __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) @@ -428,12 +430,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 044a96ca45..426b64c352 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -217,6 +217,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) @@ -228,12 +231,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -288,24 +293,42 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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) - .flash.tbss (NOLOAD) : - { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_noload)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -318,7 +341,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] diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index fba4a6f40f..2e706172d5 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/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) @@ -357,12 +360,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -417,24 +422,42 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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) - .flash.tbss (NOLOAD) : - { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_noload)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -447,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] diff --git a/components/esp_system/ld/esp32c5/sections.ld.in b/components/esp_system/ld/esp32c5/sections.ld.in index 1b74d282bc..4c595552ad 100644 --- a/components/esp_system/ld/esp32c5/sections.ld.in +++ b/components/esp_system/ld/esp32c5/sections.ld.in @@ -402,6 +402,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) @@ -413,12 +416,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -473,32 +478,48 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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.*) + _thread_local_data_end = ABSOLUTE(.); - . = ALIGN(ALIGNOF(.flash.tbss)); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.rodata_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 - - _thread_local_data_end = ABSOLUTE(.); - } > default_rodata_seg - ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) - - .flash.tbss (NOLOAD) : - { - _thread_local_bss_start = ABSOLUTE(.); - - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon .tcommon.*) - - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -511,7 +532,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] diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index b1384433e3..2ab1fcca85 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -398,6 +398,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) @@ -409,12 +412,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -469,24 +474,42 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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) - .flash.tbss (NOLOAD) : - { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_noload)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -499,7 +522,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] diff --git a/components/esp_system/ld/esp32c61/sections.ld.in b/components/esp_system/ld/esp32c61/sections.ld.in index 628bb3b900..156e0df023 100644 --- a/components/esp_system/ld/esp32c61/sections.ld.in +++ b/components/esp_system/ld/esp32c61/sections.ld.in @@ -244,6 +244,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) @@ -255,6 +258,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(.); @@ -262,6 +266,7 @@ SECTIONS KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -316,32 +321,48 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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.*) + _thread_local_data_end = ABSOLUTE(.); - . = ALIGN(ALIGNOF(.flash.tbss)); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.rodata_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 - - _thread_local_data_end = ABSOLUTE(.); - } > default_rodata_seg - ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) - - .flash.tbss (NOLOAD) : - { - _thread_local_bss_start = ABSOLUTE(.); - - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon .tcommon.*) - - _thread_local_bss_end = ABSOLUTE(.); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -354,7 +375,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] diff --git a/components/esp_system/ld/esp32h2/sections.ld.in b/components/esp_system/ld/esp32h2/sections.ld.in index 4d4c5293c8..a2e5c19b10 100644 --- a/components/esp_system/ld/esp32h2/sections.ld.in +++ b/components/esp_system/ld/esp32h2/sections.ld.in @@ -400,6 +400,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) @@ -411,12 +414,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -471,24 +476,42 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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) - .flash.tbss (NOLOAD) : - { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_noload)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -501,7 +524,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] diff --git a/components/esp_system/ld/esp32h21/sections.ld.in b/components/esp_system/ld/esp32h21/sections.ld.in index 1d6ec0fc2e..76d94a3e58 100644 --- a/components/esp_system/ld/esp32h21/sections.ld.in +++ b/components/esp_system/ld/esp32h21/sections.ld.in @@ -389,6 +389,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) @@ -400,12 +403,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -460,24 +465,42 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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) - .flash.tbss (NOLOAD) : - { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_noload)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -490,7 +513,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] diff --git a/components/esp_system/ld/esp32h4/sections.ld.in b/components/esp_system/ld/esp32h4/sections.ld.in index bc355709e3..f3201e90ff 100644 --- a/components/esp_system/ld/esp32h4/sections.ld.in +++ b/components/esp_system/ld/esp32h4/sections.ld.in @@ -218,6 +218,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) @@ -229,12 +232,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -289,24 +294,42 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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) - .flash.tbss (NOLOAD) : - { + /* tbss sections */ _thread_local_bss_start = ABSOLUTE(.); - *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon .tcommon.*) - _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_noload)); } > default_rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -319,7 +342,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] diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in index 2e3d85f6bf..e41bb6bc83 100644 --- a/components/esp_system/ld/esp32p4/sections.ld.in +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -426,6 +426,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) @@ -443,12 +446,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -503,32 +508,48 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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.*) + _thread_local_data_end = ABSOLUTE(.); - . = ALIGN(ALIGNOF(.flash.tbss)); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.rodata_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 - - _thread_local_data_end = ABSOLUTE(.); - } > rodata_seg_low - ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) - - .flash.tbss (NOLOAD) : - { - _thread_local_bss_start = ABSOLUTE(.); - - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon .tcommon.*) - - _thread_local_bss_end = ABSOLUTE(.); } > rodata_seg_low + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -541,7 +562,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 = .; arrays[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 8163968790..137e638c22 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,12 +408,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -460,11 +465,37 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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.*) + _thread_local_data_end = ABSOLUTE(.); - . = ALIGN(ALIGNOF(.flash.tbss)); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); + + . = ALIGN(ALIGNOF(.flash.rodata_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 @@ -472,20 +503,11 @@ SECTIONS */ . = ALIGN(_esp_pmp_align_size); #endif // CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION - - _thread_local_data_end = ABSOLUTE(.); - } > rodata_seg_low - ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) - - .flash.tbss (NOLOAD) : - { - _thread_local_bss_start = ABSOLUTE(.); - - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon .tcommon.*) - - _thread_local_bss_end = ABSOLUTE(.); } > rodata_seg_low + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -498,7 +520,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 = .; 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 7f90596d34..3810f53088 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -397,12 +397,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors.*))) KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors)) __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) @@ -430,12 +432,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 52a6e7c460..a6a33cc54d 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -409,12 +409,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors.*))) KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors)) __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) @@ -442,12 +444,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/esp32s31/sections.ld.in b/components/esp_system/ld/esp32s31/sections.ld.in index ba2a6da044..c1615e74ef 100644 --- a/components/esp_system/ld/esp32s31/sections.ld.in +++ b/components/esp_system/ld/esp32s31/sections.ld.in @@ -219,6 +219,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) @@ -236,12 +239,14 @@ 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(.); ALIGNED_SYMBOL(4, __init_array_start) KEEP (*(SORT_BY_INIT_PRIORITY(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*))) 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) @@ -296,32 +301,48 @@ 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. + * + * Storing all TLS structures in flash increases binary size, but avoids + * runtime issues and reduces TLS allocations on the stack. + */ + /* 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.*) + _thread_local_data_end = ABSOLUTE(.); - . = ALIGN(ALIGNOF(.flash.tbss)); + /* tbss sections */ + _thread_local_bss_start = ABSOLUTE(.); + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon .tcommon.*) + _thread_local_bss_end = ABSOLUTE(.); + . = ALIGN(ALIGNOF(.flash.rodata_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 - - _thread_local_data_end = ABSOLUTE(.); - } > rodata_seg - ASSERT_SECTIONS_GAP(.flash.tdata, .flash.tbss) - - .flash.tbss (NOLOAD) : - { - _thread_local_bss_start = ABSOLUTE(.); - - *(.tbss .tbss.* .gnu.linkonce.tb.*) - *(.tcommon .tcommon.*) - - _thread_local_bss_end = ABSOLUTE(.); } > rodata_seg + ASSERT_SECTIONS_GAP(.flash.tdata, .flash.rodata_noload) + ASSERT(_thread_local_data_end == _thread_local_bss_start, + "tdata and tbss must be contiguous.") + ASSERT_PICOLIBC_REENT_STUB() /** * This section contains all the rodata that is not used @@ -334,7 +355,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 = .; arrays[rodata_noload] diff --git a/components/esp_system/ld/ld.common b/components/esp_system/ld/ld.common index 8f05406d21..bca6c1ecc2 100644 --- a/components/esp_system/ld/ld.common +++ b/components/esp_system/ld/ld.common @@ -120,3 +120,14 @@ ASSERT((ADDR(NEXT_SECTION) == ADDR(PREV_SECTION) + SIZEOF(PREV_SECTION)), \ #else #define FAST_REFLASHING_PADDING #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 c0f16d8502..9c7df905d1 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -197,6 +197,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) { @@ -217,6 +232,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 @@ -943,6 +962,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 3bd4ba4bfe..f5f7ec1da4 100644 --- a/components/esp_tee/CMakeLists.txt +++ b/components/esp_tee/CMakeLists.txt @@ -123,11 +123,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 b3c0e91265..cb6fd8aa30 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 ceccfe2bc1..4c3716077f 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_hal_mspi esp_hal_wdt esp_sec # 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 esp_libc soc spi_flash) diff --git a/components/esp_tee/subproject/main/CMakeLists.txt b/components/esp_tee/subproject/main/CMakeLists.txt index 9de09704c7..1e6396a004 100644 --- a/components/esp_tee/subproject/main/CMakeLists.txt +++ b/components/esp_tee/subproject/main/CMakeLists.txt @@ -70,7 +70,7 @@ idf_component_register(SRCS ${srcs} # NOTE: The ESP32-H2 and C61 ROM does not have sprintf/snprintf implementation, # thus newlib-nano implementation from the toolchain has been used. -if(CONFIG_IDF_TARGET_ESP32H2 OR CONFIG_IDF_TARGET_ESP32C61) +if(CONFIG_LIBC_NEWLIB AND (CONFIG_IDF_TARGET_ESP32H2 OR CONFIG_IDF_TARGET_ESP32C61)) target_link_libraries(${COMPONENT_LIB} INTERFACE "--specs=nano.specs") endif() @@ -85,6 +85,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 4261bd73dd..49d963a8e6 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 4062764ada..14c36dfc1f 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 48e5c3ba65..c8db9b4c87 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 f50b7e02a0..9df51df288 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 486e2782bd..656a82ae0f 100644 --- a/components/lwip/port/esp32xx/include/arch/cc.h +++ b/components/lwip/port/esp32xx/include/arch/cc.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-3-Clause * - * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD */ #ifndef __ARCH_CC_H__ #define __ARCH_CC_H__ @@ -25,10 +25,18 @@ extern "C" { #endif // BYTE_ORDER #define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#ifndef htons #define htons(x) __builtin_bswap16(x) +#endif +#ifndef ntohs #define ntohs(x) __builtin_bswap16(x) +#endif +#ifndef htonl #define htonl(x) __builtin_bswap32(x) +#endif +#ifndef ntohl #define ntohl(x) __builtin_bswap32(x) +#endif #ifndef CONFIG_LWIP_ESP_LWIP_ASSERT #define LWIP_NOASSERT 1 diff --git a/components/lwip/test_apps/main/lwip_test.c b/components/lwip/test_apps/main/lwip_test.c index 8feacb5593..1f83ecee94 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/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index c5b190397e..59bd582120 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -132,6 +132,18 @@ FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_set_cycle_count(u #endif } +FORCE_INLINE_ATTR void rv_utils_set_threadptr(void *ptr) +{ + asm volatile("mv tp, %0" :: "r"(ptr)); +} + +FORCE_INLINE_ATTR void *rv_utils_get_threadptr(void) +{ + void *thread_ptr; + asm volatile("mv %0, tp" : "=r"(thread_ptr)); + return thread_ptr; +} + /* ------------------------------------------------- CPU Interrupts ---------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ diff --git a/components/sdmmc/include/sd_protocol_defs.h b/components/sdmmc/include/sd_protocol_defs.h index f943789dc8..ba0c32f8c5 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 0b3aed5047..e317600f88 100644 --- a/components/soc/esp32p4/register/hw_ver3/soc/pmu_struct.h +++ b/components/soc/esp32p4/register/hw_ver3/soc/pmu_struct.h @@ -7,6 +7,7 @@ #include #include +#include #include "pmu_reg.h" #ifdef __cplusplus extern "C" { diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake index d98043c7b2..34b1059d4d 100644 --- a/components/soc/project_include.cmake +++ b/components/soc/project_include.cmake @@ -80,30 +80,8 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) if(NOT CONFIG_SOC_CPU_MISALIGNED_ACCESS_ON_PMP_MISMATCH_ISSUE) idf_toolchain_add_flags(COMPILE_OPTIONS "-mtune=esp-base") endif() + idf_toolchain_rerun_abi_detection() else() message(FATAL_ERROR "Unknown Espressif architecture: ${CONFIG_IDF_TARGET_ARCH}") endif() - - # Workaround: Re-run CMake compiler ABI detection after ABI flags are set. - # - # Problem: CMake performs compiler checks at an early stage during - # toolchain.cmake processing. At this early stage, response files are not yet - # ready, which causes CMake paths (e.g., CMAKE__IMPLICIT_LINK_DIRECTORIES) - # to be incorrectly determined. - # - # Solution: Re-run the ABI detection after ABI flags are present to correctly - # determine these paths. - # - # Note: If the CMake API changes, this solution may need to be revised. - set(lang_ext_pairs "C|c" "CXX|cpp") - include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) - foreach(lang_ext ${lang_ext_pairs}) - string(REPLACE "|" ";" lang_ext_parts ${lang_ext}) - list(GET lang_ext_parts 0 lang) - list(GET lang_ext_parts 1 ext) - if(DEFINED CMAKE_${lang}_ABI_COMPILED) - unset(CMAKE_${lang}_ABI_COMPILED) - cmake_determine_compiler_abi(${lang} ${CMAKE_ROOT}/Modules/CMake${lang}CompilerABI.${ext}) - endif() - endforeach() endif() diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index 517f0982fb..4a97b18ec4 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 972d8fd3e2..f841c436e9 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 94814539cd..353701cdca 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 e9cf3870ab..d496648d83 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 80f7720cca..538c5e3817 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/xtensa/include/xt_utils.h b/components/xtensa/include/xt_utils.h index ea0eb5496e..2499d54b29 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 f0b10cfaed..ccb1598dc9 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/docs/en/migration-guides/release-6.x/6.0/system.rst b/docs/en/migration-guides/release-6.x/6.0/system.rst index 4ed7c7fe15..41c5ebaf92 100644 --- a/docs/en/migration-guides/release-6.x/6.0/system.rst +++ b/docs/en/migration-guides/release-6.x/6.0/system.rst @@ -3,6 +3,71 @@ System :link_to_translation:`zh_CN:[中文]` +Default LibC changed from Newlib to PicolibC +-------------------------------------------- + +Since ESP-IDF v6.0, the default LibC used in builds has switched to the PicolibC implementation. + +.. note:: + PicolibC is a Newlib fork with a rewritten stdio implementation whose goal is to consume less memory. + +In most cases, no application behavior changes are expected, except for reduced binary size and less stack consumption on I/O operations. + +.. warning:: + **Breaking change:** It is not possible to redefine stdin, stdout, and stderr for specific tasks as was possible with Newlib. These streams are global and shared between all tasks. This is POSIX-standardized behavior. + +:ref:`CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY`, which is enabled by default, provides limited compatibility with Newlib by providing thread-local copies of global stdin, stdout, stderr, and the getreent() implementation. If a library built with Newlib headers operates with "internal" fields of "struct reent", there may be task stack corruption. Note that manipulating "struct reent" fields is expected only by the Newlib library itself. + +If you are not linking against external libraries built against Newlib headers, you may disable :ref:`CONFIG_LIBC_PICOLIBC_NEWLIB_COMPATIBILITY` to save a small amount of memory. + +Newlib is still maintained in ESP-IDF toolchains. To switch to using it, select Newlib in menuconfig via the option LIBC_NEWLIB in :ref:`CONFIG_LIBC`. + +Comparison of Newlib vs Picolibc +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are a small example that shows the motivation of switching to Picolibc: + +.. code-block:: c + + FILE *f = fopen("/dev/console", "w"); + for (int i = 0; i < 10; i++) + { + fprintf(f, "hello world %s\n", "🤖"); + fprintf(f, "%.1000f\n", 3.141592653589793); + fprintf(f, "%1000d\n", 42); + } + +The test code was compiled with both Newlib and Picolibc, and the results were compared on ESP32-C3: + +.. list-table:: Comparison of Newlib vs Picolibc + :header-rows: 1 + :widths: 30 20 20 20 + :stub-columns: 1 + + * - Metric + - Newlib + - Picolibc + - Difference + * - Binary size (bytes) + - 280,128 + - 224,656 + - 19.80% + * - Stack usage (bytes) + - 1,748 + - 802 + - 54.12% + * - Heap usage (bytes) + - 1,652 + - 376 + - 77.24% + * - Performance (CPU cycles) + - 278,232,026 + - 279,823,800 + - 0.59% + +.. note:: + Even when :ref:`CONFIG_LIBC_NEWLIB_NANO_FORMAT` is enabled, which disables float formatting, applications with Picolibc are still smaller by 6% (224,592 vs 239,888 bytes). + Xtensa ------ diff --git a/examples/ethernet/iperf/main/ethernet_iperf_main.c b/examples/ethernet/iperf/main/ethernet_iperf_main.c index cd899aad77..bd5b996ec1 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(ethernet_init_all(&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 57a14174ec..0a99292d42 100644 --- a/examples/ethernet/iperf/pytest_eth_iperf.py +++ b/examples/ethernet/iperf/pytest_eth_iperf.py @@ -28,6 +28,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""" @@ -50,9 +56,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 @@ -71,12 +75,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 aae307df62..64367a750c 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 7438715fa7..d6718311ef 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 a1a1c523b2..5eff9f616b 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(f'ping -I {interface_nr} {ipv6} -c 5') 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 cd201e60d1..508026efd2 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 abc01a900a..4e872f5e21 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 c258f05db6..4931b68fc1 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 @@ -88,7 +89,7 @@ class PublicHeaderChecker: if self.verbose or debug: print(message) - def __init__(self, verbose: bool = False, jobs: int = 1, prefix: str | None = None) -> None: + def __init__(self, libc_type: str, verbose: bool = False, jobs: int = 1, prefix: str | None = None) -> None: self.gcc = f'{prefix}gcc' self.gpp = f'{prefix}g++' self.verbose = verbose @@ -122,6 +123,7 @@ 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() @@ -131,6 +133,7 @@ class PublicHeaderChecker: if idf_path is None: raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.") self.idf_path = idf_path + self.build_dir = tempfile.mkdtemp() def __enter__(self) -> 'PublicHeaderChecker': for i in range(self.jobs): @@ -143,6 +146,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: @@ -175,14 +179,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() @@ -221,6 +244,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, @@ -311,14 +337,17 @@ class PublicHeaderChecker: def list_public_headers(self, ignore_dirs: list, ignore_files: list | set, only_dir: str | None = None) -> None: idf_path = self.idf_path 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 == 'newlib': + with open(sdkconfig, 'w') as f: + f.write('CONFIG_LIBC_NEWLIB=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: @@ -326,7 +355,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, encoding='utf-8') as f: j = json.load(f) self.stdc = get_std(j, 'c') @@ -344,13 +373,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' @@ -435,6 +464,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 @@ -452,7 +484,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/toolchain_flags.cmake b/tools/cmake/toolchain_flags.cmake index 682e4e2602..cd273040fd 100644 --- a/tools/cmake/toolchain_flags.cmake +++ b/tools/cmake/toolchain_flags.cmake @@ -155,3 +155,28 @@ endfunction() function(idf_toolchain_remove_flags) _process_toolchain_flag_options() endfunction() + +# Workaround: Re-run CMake compiler ABI detection after ABI flags are set. +# +# Problem: CMake performs compiler checks at an early stage during +# toolchain.cmake processing. At this early stage, response files are not yet +# ready, which causes CMake paths (e.g., CMAKE__IMPLICIT_LINK_DIRECTORIES) +# to be incorrectly determined. +# +# Solution: Re-run the ABI detection after ABI flags are present to correctly +# determine these paths. +# +# Note: If the CMake API changes, this solution may need to be revised. +macro(idf_toolchain_rerun_abi_detection) + set(lang_ext_pairs "C|c" "CXX|cpp") + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + foreach(lang_ext ${lang_ext_pairs}) + string(REPLACE "|" ";" lang_ext_parts ${lang_ext}) + list(GET lang_ext_parts 0 lang) + list(GET lang_ext_parts 1 ext) + if(DEFINED CMAKE_${lang}_ABI_COMPILED) + unset(CMAKE_${lang}_ABI_COMPILED) + cmake_determine_compiler_abi(${lang} ${CMAKE_ROOT}/Modules/CMake${lang}CompilerABI.${ext}) + endif() + endforeach() +endmacro() diff --git a/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c b/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c index dbbc75263e..2372c22f30 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_apps/system/init_array/main/test_app_main.c b/tools/test_apps/system/init_array/main/test_app_main.c index 545e9800c1..79cbbe2162 100644 --- a/tools/test_apps/system/init_array/main/test_app_main.c +++ b/tools/test_apps/system/init_array/main/test_app_main.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include +#include __attribute__((constructor)) void foo(void) diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index 724baf120d..4600b54cf0 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -1159,6 +1159,7 @@ def spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func @pytest.mark.generic +@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='TODO IDF-14835') @idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP, indirect=['config', 'target']) def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: spiram_xip_irom_alignment_reg_execute_violation(dut, test_func_name) @@ -1187,6 +1188,7 @@ def spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func @pytest.mark.generic +@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='TODO IDF-14835') @idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP, indirect=['config', 'target']) def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: spiram_xip_drom_alignment_reg_execute_violation(dut, test_func_name) diff --git a/tools/tools.json b/tools/tools.json index 592bf44627..8dad94dda9 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -183,51 +183,51 @@ "versions": [ { "linux-amd64": { - "sha256": "178377e249346c232323cb94f052cdd0b83fcd581db2e2297e629e034243edcf", - "size": 123613880, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-x86_64-linux-gnu.tar.xz" + "sha256": "7db5f3d70955e71013dd56a6cec5cf34945686641dac16315f552d0b58ec8dec", + "size": 175992400, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "2b79b7b8bf353e42dd1c0aa1d7f06dc681b2c7696d3d82e8cce73c78d0fc517c", - "size": 123216052, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-aarch64-linux-gnu.tar.xz" + "sha256": "7e3ff4da48839f5aa1f1cc7556d770e68e1a008dd2acef48e226a8f038a9eee3", + "size": 170387832, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-aarch64-linux-gnu.tar.xz" }, "linux-armel": { - "sha256": "f800994451531037b465887588b442e85155a1a55e276cf99f04752d33e3d4f3", - "size": 114565516, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-arm-linux-gnueabi.tar.xz" + "sha256": "772e0e3cf9851472527a871f510a632abb63be27503e2e7fc14309d97547a729", + "size": 168192800, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-arm-linux-gnueabi.tar.xz" }, "linux-armhf": { - "sha256": "55b71f4dfcbfbe6edd3ee890a213ade28e09cd05d52d1b702f64985352753d72", - "size": 118207548, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-arm-linux-gnueabihf.tar.xz" + "sha256": "0735737f4c124470eadd17062f4bb29ab35184fa29adf4b82b851aafb1b84e5d", + "size": 169364908, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-arm-linux-gnueabihf.tar.xz" }, "linux-i686": { - "sha256": "074b958b53008ff26e721762381109c50cdd5924de49d83f0d6aea118c786e4d", - "size": 128852676, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-i586-linux-gnu.tar.xz" + "sha256": "0a4313844b332cebdb5c02c3ffcc13a3f7e5251371143ed045f6f003160adc8c", + "size": 180963052, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-i586-linux-gnu.tar.xz" }, "macos": { - "sha256": "d5c1f617d7a82d95c9b91aa16293788436695068a9a8b7ac85324038c9476dc6", - "size": 118844368, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-x86_64-apple-darwin.tar.xz" + "sha256": "1f5af1d5c6a4b9334c2bb17517ed4c57f1561b07806bd6b3d8a18f43c18d6fa9", + "size": 176235436, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "6e3f75d248e6226be5806192bd0619c9e2b43cfeee3211f47035a04b08612d0a", - "size": 112979600, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-aarch64-apple-darwin.tar.xz" + "sha256": "7c059ec59a0d23e9a864dccd708891787c37ae26dfead5ce4ea9c76e9404fa88", + "size": 170365504, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-aarch64-apple-darwin.tar.xz" }, - "name": "esp-15.2.0_20250929", + "name": "esp-15.2.0_20251201", "status": "recommended", "win32": { - "sha256": "3113e6f6982fc6ed0ce9e2c571e09250b63f074dab11e22066fdc454a1f7161d", - "size": 315688126, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-i686-w64-mingw32.zip" + "sha256": "b848f492b806458f9da6871295c9a323cb55f9ee988d5b83b6bfe017d67377a2", + "size": 404554525, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-i686-w64-mingw32.zip" }, "win64": { - "sha256": "e352f10b641b537384df6c20a128316f27895f90d0b417f7313e58d1418e0768", - "size": 317567871, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/xtensa-esp-elf-15.2.0_20250929-x86_64-w64-mingw32.zip" + "sha256": "963667e4d8f79010d8b443741bbe89633bcdbbe478dc68f18df9fc68561404da", + "size": 406434766, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/xtensa-esp-elf-15.2.0_20251201-x86_64-w64-mingw32.zip" } } ] @@ -401,51 +401,51 @@ "versions": [ { "linux-amd64": { - "sha256": "516abd1c8e9646d8b846f180d7c06d95494822df93aa967e097c6591f6e4d4d6", - "size": 272918656, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-x86_64-linux-gnu.tar.xz" + "sha256": "f56784438bbb09e038932384c7227000e1ff3add77e8da40c9fe49e0fd5faed5", + "size": 393889356, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "d38feff577a343a9b0bab2d546e2b0c8ff7e3e6785dec941e8ea567b5c7a23b1", - "size": 262216336, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-aarch64-linux-gnu.tar.xz" + "sha256": "16ba372e9d48efbfc650ee3a942c030cffe6579e387cf2df5a2f5fb88936e2bc", + "size": 377121260, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-aarch64-linux-gnu.tar.xz" }, "linux-armel": { - "sha256": "c5baa48f1c9d08b8252342285fb89686ab8ccfcf069a3efc7842b2c59e7a7975", - "size": 252770280, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-arm-linux-gnueabi.tar.xz" + "sha256": "963c3bf584a938c059a0e774dc2f404eb317363acadfd0a24a52b86ee7691501", + "size": 374889380, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-arm-linux-gnueabi.tar.xz" }, "linux-armhf": { - "sha256": "df0ffe886d6934b375b0002759f0e6c4bf76d66ea89e12255ab6c0740ef60806", - "size": 252160556, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-arm-linux-gnueabihf.tar.xz" + "sha256": "e9d3101120e1138dfb0fa143915e1fcb1c8d0bc703a482fee816024b43d642fd", + "size": 375080852, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-arm-linux-gnueabihf.tar.xz" }, "linux-i686": { - "sha256": "d424944b7277c16936928737e6c644b0f5cdb4c29e45f421e0bef0020ce8ce23", - "size": 265575540, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-i586-linux-gnu.tar.xz" + "sha256": "3214b3726e3314f2165ec779ec663fa57f3270463ab73616a2432da209d3001f", + "size": 390028812, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-i586-linux-gnu.tar.xz" }, "macos": { - "sha256": "b16b934b2d7c1c5a27e512c74db795a1913ea141bcea295529d065c9612fe046", - "size": 274668308, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-x86_64-apple-darwin.tar.xz" + "sha256": "6b8f275488f16dc907c2b512549c3e89b7267de900677a81525d69ed4959afac", + "size": 397332472, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "df2a485c0a3133c7a023be9a57853c0861ca318bbcbf86f26e422ad86bdbbe5e", - "size": 266820448, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-aarch64-apple-darwin.tar.xz" + "sha256": "fbc5738120ef0da03ac0bc3f11c07ed393551a2741cf6aad65fa97bccc63dba4", + "size": 389500768, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-aarch64-apple-darwin.tar.xz" }, - "name": "esp-15.2.0_20250929", + "name": "esp-15.2.0_20251201", "status": "recommended", "win32": { - "sha256": "bc34d1110070cc5c6a232597d2585255f8132a2c35fd8485a9764c78dc5d80d3", - "size": 694303425, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-i686-w64-mingw32.zip" + "sha256": "0635a6b82f075d9b68854677b1bc58599b0e2e129242e8eaf7a2244313cf564c", + "size": 956267209, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-i686-w64-mingw32.zip" }, "win64": { - "sha256": "b30e667cbcddbe08415a049489380b0a484e5ed243d0f1f4dbb6891b5e5e2252", - "size": 701518640, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20250929/riscv32-esp-elf-15.2.0_20250929-x86_64-w64-mingw32.zip" + "sha256": "20eac8ca3e8496f9f8b3942202571c8ee1203e0a4516858b68f8cdcab0e72076", + "size": 963485264, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-15.2.0_20251201/riscv32-esp-elf-15.2.0_20251201-x86_64-w64-mingw32.zip" } } ]