From ed4275854954a585ad19d5529aabd618d533b9bb Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Thu, 17 Dec 2020 11:17:08 +0800 Subject: [PATCH] [cxx/system]: fix init_priority ordering on RISCV * C++ init_priority attributes work now on RISCV * Add debug output for init_array functions Closes IDF-2206 Closes https://github.com/espressif/esp-idf/issues/6351 --- components/cxx/test/test_initialization.cpp | 14 ++++++------- components/esp32c3/ld/esp32c3.project.ld.in | 17 ++++++++++++--- components/esp_system/startup.c | 23 +++++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/components/cxx/test/test_initialization.cpp b/components/cxx/test/test_initialization.cpp index cbfad66e8c..6d5ced3061 100644 --- a/components/cxx/test/test_initialization.cpp +++ b/components/cxx/test/test_initialization.cpp @@ -180,14 +180,14 @@ struct PriorityInitTest int PriorityInitTest::order = 0; // init_priority objects are initialized from the lowest to the heighest priority number -// Default init_priority is always the lowest -PriorityInitTest g_static_init_priority_test3; -PriorityInitTest g_static_init_priority_test2 __attribute__((init_priority(1000))); -PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(999))); +// Default init_priority is always the lowest (highest priority number) +PriorityInitTest g_static_init_priority_test2; +PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000))); +PriorityInitTest g_static_init_priority_test0 __attribute__((init_priority(999))); TEST_CASE("init_priority extension works", "[cxx]") { - TEST_ASSERT_EQUAL(0, g_static_init_priority_test1.index); - TEST_ASSERT_EQUAL(1, g_static_init_priority_test2.index); - TEST_ASSERT_EQUAL(2, g_static_init_priority_test3.index); + TEST_ASSERT_EQUAL(0, g_static_init_priority_test0.index); + TEST_ASSERT_EQUAL(1, g_static_init_priority_test1.index); + TEST_ASSERT_EQUAL(2, g_static_init_priority_test2.index); } diff --git a/components/esp32c3/ld/esp32c3.project.ld.in b/components/esp32c3/ld/esp32c3.project.ld.in index 687f5128ec..cf536223b5 100644 --- a/components/esp32c3/ld/esp32c3.project.ld.in +++ b/components/esp32c3/ld/esp32c3.project.ld.in @@ -304,10 +304,21 @@ SECTIONS __eh_frame = ABSOLUTE(.); KEEP(*(.eh_frame)) . = (. + 7) & ~ 3; - /* C++ constructor and destructor tables */ - /* Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt */ + /* + * C++ constructor and destructor tables + * Don't include anything from crtbegin.o or crtend.o, as IDF doesn't use toolchain crt. + * + * RISC-V gcc is configured with --enable-initfini-array so it emits an .init_array section instead. + * But the init_priority sections will be sorted for iteration in ascending order during startup. + * The rest of the init_array sections is sorted for iteration in descending order during startup, however. + * Hence a different section is generated for the init_priority functions which is iterated in + * ascending order during startup. The corresponding code can be found in startup.c. + */ + __init_priority_array_start = ABSOLUTE(.); + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array.*)) + __init_priority_array_end = ABSOLUTE(.); __init_array_start = ABSOLUTE(.); - KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array .ctors .ctors.*)) + KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .init_array)) __init_array_end = ABSOLUTE(.); KEEP (*crtbegin.*(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index d8f4d039d5..4fb9f674b6 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -129,8 +129,22 @@ static IRAM_ATTR void _Unwind_SetNoFunctionContextInstall_Default(unsigned char static const char* TAG = "cpu_start"; +/** + * Xtensa gcc is configured to emit a .ctors section, RISC-V gcc is configured with --enable-initfini-array + * so it emits an .init_array section instead. + * But the init_priority sections will be sorted for iteration in ascending order during startup. + * The rest of the init_array sections is sorted for iteration in descending order during startup, however. + * Hence a different section is generated for the init_priority functions which is looped + * over in ascending direction instead of descending direction. + * The RISC-V-specific behavior is dependent on the linker script esp32c3.project.ld.in. + */ static void do_global_ctors(void) { +#if __riscv + extern void (*__init_priority_array_start)(void); + extern void (*__init_priority_array_end)(void); +#endif + extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); @@ -144,7 +158,16 @@ static void do_global_ctors(void) #endif // CONFIG_COMPILER_CXX_EXCEPTIONS void (**p)(void); + +#if __riscv + for (p = &__init_priority_array_start; p < &__init_priority_array_end; ++p) { + ESP_EARLY_LOGD(TAG, "calling init function: %p", *p); + (*p)(); + } +#endif + for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { + ESP_EARLY_LOGD(TAG, "calling init function: %p", *p); (*p)(); } }