Skip to content

Commit

Permalink
linker: ensure global constructors only run once
Browse files Browse the repository at this point in the history
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 zephyrproject-rtos#39347, zephyrproject-rtos#36858

Signed-off-by: David Palchak <palchak@google.com>
  • Loading branch information
palchak-google authored and Wouter Cappelle committed Oct 7, 2022
1 parent 3fee92a commit 7bfa184
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 14 deletions.
35 changes: 30 additions & 5 deletions include/zephyr/linker/common-rom/common-rom-cpp.ld
Expand Up @@ -9,29 +9,54 @@
* 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
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)

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
2 changes: 1 addition & 1 deletion kernel/init.c
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions subsys/cpp/cpp_ctors.c
Expand Up @@ -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__[];

/**
*
Expand All @@ -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--]();
}
}
8 changes: 4 additions & 4 deletions subsys/cpp/cpp_init_array.c
Expand Up @@ -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)();
}
Expand Down

0 comments on commit 7bfa184

Please sign in to comment.