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 * boundary. To align with the C++ standard, the first element
* of the array contains the number of actual constructors. The * of the array contains the number of actual constructors. The
* last element is NULL. * 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 #ifdef CONFIG_64BIT
. = ALIGN(8); . = ALIGN(8);
__CTOR_LIST__ = .; __ZEPHYR_CTOR_LIST__ = .;
QUAD((__CTOR_END__ - __CTOR_LIST__) / 8 - 2) QUAD((__ZEPHYR_CTOR_END__ - __ZEPHYR_CTOR_LIST__) / 8 - 2)
KEEP(*(SORT_BY_NAME(".ctors*"))) KEEP(*(SORT_BY_NAME(".ctors*")))
__CTOR_LIST__ = .;
QUAD(0)
__ZEPHYR_CTOR_END__ = .;
QUAD(0) QUAD(0)
__CTOR_END__ = .; __CTOR_END__ = .;
#else #else
. = ALIGN(4); . = ALIGN(4);
__CTOR_LIST__ = .; __ZEPHYR_CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) LONG((__ZEPHYR_CTOR_END__ - __ZEPHYR_CTOR_LIST__) / 4 - 2)
KEEP(*(SORT_BY_NAME(".ctors*"))) KEEP(*(SORT_BY_NAME(".ctors*")))
__CTOR_LIST__ = .;
LONG(0)
__ZEPHYR_CTOR_END__ = .;
LONG(0) LONG(0)
__CTOR_END__ = .; __CTOR_END__ = .;
#endif #endif
@ -29,9 +43,20 @@
SECTION_PROLOGUE(init_array,,) 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); . = ALIGN(4);
__init_array_start = .; __init_array_start = .;
KEEP(*(SORT_BY_NAME(".init_array*")))
__init_array_end = .; __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) } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#endif #endif

View file

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

View file

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

View file

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