Просмотр исходного кода

Merge branch 'bugfix/c3_init_priority' into 'master'

fix[cxx/system]: init_priority ordering on RISCV

Closes IDF-2206 and IDFGH-4527

See merge request espressif/esp-idf!11660
Angus Gratton 5 лет назад
Родитель
Сommit
820639cede

+ 7 - 7
components/cxx/test/test_initialization.cpp

@@ -180,17 +180,17 @@ 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)));
 
 #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)
 // TODO ESP32C3 IDF-2206
 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);
 }
 #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32C3)

+ 14 - 3
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))

+ 23 - 0
components/esp_system/startup.c

@@ -134,8 +134,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);
 
@@ -149,7 +163,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)();
     }
 }