diff options
| author | seteiro <[email protected]> | 2026-10-10 20:34:34 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-10-11 16:11:07 +0800 |
| commit | 3577e7a6ed0f183534e207179de5251e155fd49e (patch) | |
| tree | 424c4f10acd38b0807e7cfe25db1af1e92a44136 /components | |
| parent | 33b1dd58bafbd850e982191b5f138cf8d7578e61 (diff) | |
[components][libc] run .init_array constructors in cplusplus_system_init
Newer GCC emits C++ global constructors into .init_array, which many
linker scripts keep outside [__ctors_start__, __ctors_end__), so they
never ran. Walk __init_array_start/__init_array_end (weak) as well,
skipping entries already covered by the ctors range.
Add RT_USING_CPP_CRT_INIT for ports whose startup runtime already runs
.init_array, default on for the simulator. With it set, only the
.init_array walk is skipped; the ctors range is still walked.
Renesas RA/RA_WIRELESS/RZ families select it when C++ is enabled: FSP
SystemInit() already walks .init_array, so boards whose linker script
only provides __init_array_* would run constructors twice. Boards that
fold .init_array into the ctors range (ra6m3-hmi-board, ra8d1, rz)
still run them once via RT-Thread.
Also source env.sh and restore RTT_EXEC_PATH in ToolsCI project generate
and dist steps so scons is on PATH (exit 127) and the ARM toolchain path
is not overwritten by env.sh.
Fixes #11778
Diffstat (limited to 'components')
| -rw-r--r-- | components/libc/cplusplus/Kconfig | 13 | ||||
| -rw-r--r-- | components/libc/cplusplus/cxx_crt_init.c | 43 |
2 files changed, 50 insertions, 6 deletions
diff --git a/components/libc/cplusplus/Kconfig b/components/libc/cplusplus/Kconfig index 1dcc6f389c..749a3ab0a5 100644 --- a/components/libc/cplusplus/Kconfig +++ b/components/libc/cplusplus/Kconfig @@ -4,6 +4,19 @@ menuconfig RT_USING_CPLUSPLUS if RT_USING_CPLUSPLUS + config RT_USING_CPP_CRT_INIT + bool "Startup runtime already runs .init_array constructors" + default y if SOC_SIMULATOR + default n + help + Enable this for GCC ports whose startup runtime already walks the + .init_array section, so that RT-Thread skips it and does not run + the constructors twice. RT-Thread still walks the ctors range. + This option is usually set by the BSP; do not change it manually. + Leave this disabled when the startup code relies on the empty + __libc_init_array provided by RT-Thread's newlib port, which + defers constructors to RT-Thread. + config RT_USING_CPLUSPLUS11 bool "Enable C++11 standard multi-threading feature support" default n diff --git a/components/libc/cplusplus/cxx_crt_init.c b/components/libc/cplusplus/cxx_crt_init.c index c5d1e434b5..be8619051f 100644 --- a/components/libc/cplusplus/cxx_crt_init.c +++ b/components/libc/cplusplus/cxx_crt_init.c @@ -40,8 +40,8 @@ rt_weak void *__dso_handle = 0; * @note If there is no SHT$$INIT_ARRAY section, calling $Super$$__cpp_initialize__aeabi_() will cause an error * in ARMCC compiler. Therefore, this function manually iterates through the base addresses of the * SHT$$INIT_ARRAY section to call the constructor functions of each object. In GCC compiler, this function - * uses the __ctors_start__ and __ctors_end__ global variables to determine the range of constructor function - * pointers and calls each constructor function of every object in that range. + * always walks the ctors range; RT_USING_CPP_CRT_INIT only indicates that the startup runtime already + * walked the init_array range. * * @return Returns 0 if the initialization of the C++ runtime environment is successful. Otherwise, it returns * an error code indicating the failure of the operation. @@ -67,12 +67,43 @@ rt_weak int cplusplus_system_init(void) } #elif defined(__GNUC__) typedef void(*pfunc)(); - extern pfunc __ctors_start__[]; - extern pfunc __ctors_end__[]; + /* Linker scripts may provide the ctors range, the init_array range, or both. */ + extern pfunc __ctors_start__[] __attribute__((weak)); + extern pfunc __ctors_end__[] __attribute__((weak)); + pfunc *ctors_start = __ctors_start__; + pfunc *ctors_end = __ctors_end__; +#ifndef RT_USING_CPP_CRT_INIT + extern pfunc __init_array_start[] __attribute__((weak)); + extern pfunc __init_array_end[] __attribute__((weak)); + pfunc *init_start = __init_array_start; + pfunc *init_end = __init_array_end; +#endif pfunc *p; - for (p = __ctors_start__; p < __ctors_end__; p++) - (*p)(); + if (ctors_start && ctors_end) + { + for (p = ctors_start; (uintptr_t)p < (uintptr_t)ctors_end; p++) + { + (*p)(); + } + } + +#ifndef RT_USING_CPP_CRT_INIT + if (init_start && init_end) + { + for (p = init_start; (uintptr_t)p < (uintptr_t)init_end; p++) + { + /* Skip entries already called through the ctors range. */ + if (ctors_start && ctors_end && + (uintptr_t)p >= (uintptr_t)ctors_start && + (uintptr_t)p < (uintptr_t)ctors_end) + { + continue; + } + (*p)(); + } + } +#endif #endif return 0; |
