[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
This commit is contained in:
Jakob Hasse 2020-12-17 11:17:08 +08:00
parent 16291ba7f5
commit ed42758549
3 changed files with 44 additions and 10 deletions

View File

@ -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);
}

View File

@ -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))

View File

@ -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)();
}
}