linker: ensure global constructors only run once

Rename the symbols used to denote the locations of the global
constructor lists and modify the Zephyr start-up code accordingly.
On POSIX systems this ensures that the native libc init code won't
find any constructors to run before Zephyr loads.

Fixes #39347, #36858

Signed-off-by: David Palchak <palchak@google.com>
This commit is contained in:
David Palchak 2022-06-07 15:25:37 -07:00 committed by Carles Cufí
commit b4a7f0f2ca
4 changed files with 39 additions and 14 deletions

View file

@ -9,19 +9,33 @@
* boundary. To align with the C++ standard, the first element
* of the array contains the number of actual constructors. The
* last element is NULL.
*
* The __CTOR_LIST__ and __CTOR_END__ symbols are always defined
* to result in an empty list. This is necessary to fix an issue
* where the glibc process initialization code on native_posix
* platforms calls constructors before Zephyr loads (issue #39347).
*
* Zephyr's start-up code uses the __ZEPHYR_CTOR_LIST__ and
* __ZEHPYR_CTOR_END__ symbols, so these need to be correctly set.
*/
#ifdef CONFIG_64BIT
. = ALIGN(8);
__CTOR_LIST__ = .;
QUAD((__CTOR_END__ - __CTOR_LIST__) / 8 - 2)
__ZEPHYR_CTOR_LIST__ = .;
QUAD((__ZEPHYR_CTOR_END__ - __ZEPHYR_CTOR_LIST__) / 8 - 2)
KEEP(*(SORT_BY_NAME(".ctors*")))
__CTOR_LIST__ = .;
QUAD(0)
__ZEPHYR_CTOR_END__ = .;
QUAD(0)
__CTOR_END__ = .;
#else
. = ALIGN(4);
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
__ZEPHYR_CTOR_LIST__ = .;
LONG((__ZEPHYR_CTOR_END__ - __ZEPHYR_CTOR_LIST__) / 4 - 2)
KEEP(*(SORT_BY_NAME(".ctors*")))
__CTOR_LIST__ = .;
LONG(0)
__ZEPHYR_CTOR_END__ = .;
LONG(0)
__CTOR_END__ = .;
#endif
@ -29,9 +43,20 @@
SECTION_PROLOGUE(init_array,,)
{
/*
* Similar to the schenanigans required for the __CTOR_LIST__ and
* __CTOR_END__ symbols we define __init_array_start and __init_array_end
* to the same address to define an empty list. This prevents the glibc
* startup code from calling any global constructors before Zephyr loads.
*
* Zephyr's start-up code uses the __zephyr_init_array_start and
* __zephyr_init_array_end sybmols, so these need to be set correctly.
*/
. = ALIGN(4);
__init_array_start = .;
KEEP(*(SORT_BY_NAME(".init_array*")))
__init_array_end = .;
__zephyr_init_array_start = .;
KEEP(*(SORT_BY_NAME(".init_array*")))
__zephyr_init_array_end = .;
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#endif

View file

@ -216,7 +216,7 @@ static void bg_thread_main(void *unused1, void *unused2, void *unused3)
#endif
boot_banner();
#if defined(CONFIG_CPLUSPLUS) && !defined(CONFIG_ARCH_POSIX)
#if defined(CONFIG_CPLUSPLUS)
void z_cpp_init_static(void);
z_cpp_init_static();
#endif

View file

@ -21,8 +21,8 @@ typedef void (*CtorFuncPtr)(void);
/* Constructor function pointer list is generated by the linker script. */
extern CtorFuncPtr __CTOR_LIST__[];
extern CtorFuncPtr __CTOR_END__[];
extern CtorFuncPtr __ZEPHYR_CTOR_LIST__[];
extern CtorFuncPtr __ZEPHYR_CTOR_END__[];
/**
*
@ -35,9 +35,9 @@ void __do_global_ctors_aux(void)
{
unsigned int nCtors;
nCtors = (unsigned long)__CTOR_LIST__[0];
nCtors = (unsigned long)__ZEPHYR_CTOR_LIST__[0];
while (nCtors >= 1U) {
__CTOR_LIST__[nCtors--]();
__ZEPHYR_CTOR_LIST__[nCtors--]();
}
}

View file

@ -11,16 +11,16 @@
typedef void (*func_ptr)(void);
extern func_ptr __init_array_start[];
extern func_ptr __init_array_end[];
extern func_ptr __zephyr_init_array_start[];
extern func_ptr __zephyr_init_array_end[];
/**
* @brief Execute initialization routines referenced in .init_array section
*/
void __do_init_array_aux(void)
{
for (func_ptr *func = __init_array_start;
func < __init_array_end;
for (func_ptr *func = __zephyr_init_array_start;
func < __zephyr_init_array_end;
func++) {
(*func)();
}