Skip to content

Commit

Permalink
kernel: Unify .ctors and .init_array handling
Browse files Browse the repository at this point in the history
Handle both of these sections in a single chunk of code instead of
separately. We don't need to use the legacy .ctors ABI as both
the constructors array and startup logic are managed within a single
link result.

This can now also be used with ARC MWDT which had been using the .ctors
sections but with .init_array semantics. For ARC MWDT, we now always
discard .dtors and .fini sections as Zephyr will never cause global
destructors to execute. Stop discarding .eh_frame sections so that
exception handling works as expected.

Signed-off-by: Keith Packard <[email protected]>
  • Loading branch information
keith-packard committed Aug 22, 2024
1 parent 2462d0e commit 9847555
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 163 deletions.
11 changes: 1 addition & 10 deletions include/zephyr/arch/arc/v2/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,6 @@ SECTIONS {
#include <snippets-rodata.ld>
#include <zephyr/linker/kobject-rom.ld>

#if defined(CONFIG_CPP) && !defined(CONFIG_STATIC_INIT_GNU) && defined(__MWDT_LINKER_CMD__)
. = ALIGN(4);
_fctors = .;
KEEP(*(.ctors*))
_ectors = .;
#endif /* CONFIG_CPP && !CONFIG_STATIC_INIT_GNU && __MWDT_LINKER_CMD__ */

/* This extra MPU alignment of RAMABLE_REGION is only required if we put ROMABLE_REGION and
* RAMABLE_REGION into the same (continuous) memory - otherwise we can get beginning of the
* RAMABLE_REGION in the end of ROMABLE_REGION MPU aperture.
Expand Down Expand Up @@ -311,11 +304,9 @@ SECTIONS {
#endif

/DISCARD/ : {
#if defined(CONFIG_CPP) && !defined(CONFIG_STATIC_INIT_GNU) && defined(__MWDT_LINKER_CMD__)
/* Discard all destructors */
*(.dtors*)
*(.fini*)
*(.eh_frame*)
#endif /* CONFIG_CPP && !CONFIG_STATIC_INIT_GNU && __MWDT_LINKER_CMD__ */
*(.note.GNU-stack)
*(.got.plt)
*(.igot.plt)
Expand Down
75 changes: 24 additions & 51 deletions include/zephyr/linker/common-rom/common-rom-init.ld
Original file line number Diff line number Diff line change
@@ -1,76 +1,49 @@
/* SPDX-License-Identifier: Apache-2.0 */

#ifdef CONFIG_STATIC_INIT_GNU
SECTION_PROLOGUE(_CTOR_SECTION_NAME,,)
#ifdef CONFIG_TOOLCHAIN_SUPPORTS_STATIC_INIT_GNU
SECTION_PROLOGUE(init_array,,)
{
/*
* The compiler fills the constructor pointers table below,
* hence symbol __CTOR_LIST__ must be aligned on word
* 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.
* Add all of the GNU-style constructors in priority order. Note
* that this doesn't build the ctors in the "usual" fashion with
* a length value first and NULL terminator, but as we run this
* list ourselves, that doesn't matter.
*/
__zephyr_init_array_start = .;
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*)
SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array .ctors))
__zephyr_init_array_end = .;
#ifdef CONFIG_NATIVE_LIBC
/*
* 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).
*/
#ifdef CONFIG_64BIT
. = ALIGN(8);
__ZEPHYR_CTOR_LIST__ = .;
QUAD((__ZEPHYR_CTOR_END__ - __ZEPHYR_CTOR_LIST__) / 8 - 2)
KEEP(*(SORT_BY_NAME(".ctors*")))
__CTOR_LIST__ = .;
#ifdef CONFIG_64BIT
QUAD(0)
__ZEPHYR_CTOR_END__ = .;
QUAD(0)
__CTOR_END__ = .;
#else
. = ALIGN(4);
__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)
#endif
__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 = .;
__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)

#elif defined(CONFIG_TOOLCHAIN_SUPPORTS_STATIC_INIT_GNU) && !defined(CONFIG_NATIVE_APPLICATION)
/*
* If the code to invoke constructors is not enabled,
* make sure there aren't any in the application
*/
SECTION_PROLOGUE(init_array,,)
{
KEEP(*(SORT_BY_NAME(".ctors*")))
KEEP(*(SORT_BY_NAME(".init_array*")))
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#ifndef CONFIG_STATIC_INIT_GNU
ASSERT(__zephyr_init_array_start == __zephyr_init_array_end,
"GNU-style constructors required but STATIC_INIT_GNU not enabled")
#endif

ASSERT (SIZEOF(init_array) == 0,
"GNU-style constructors required but STATIC_INIT_GNU not enabled")
#endif
1 change: 0 additions & 1 deletion kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ list(APPEND kernel_files
errno.c
fatal.c
init.c
init_static.c
kheap.c
mem_slab.c
float.c
Expand Down
21 changes: 9 additions & 12 deletions kernel/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -970,10 +970,10 @@ config KERNEL_WHOLE_ARCHIVE
to be included, rather than searching the archive for required object files.

config TOOLCHAIN_SUPPORTS_STATIC_INIT_GNU
# As of today only ARC MWDT toolchain doesn't support GNU-compatible
# initialization of static objects, new toolchains can be added
# here if required.
def_bool "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "arcmwdt"
# As of today, we don't know of any toolchains that don't create
# either .ctors or .init_array sections containing initializer
# addresses in a fashion compatible with how Zephyr uses them.
def_bool y

config STATIC_INIT_GNU
bool "Support GNU-compatible initializers and constructors"
Expand All @@ -983,14 +983,11 @@ config STATIC_INIT_GNU
help
GNU-compatible initialization of static objects. This is required for
C++ constructor support as well as for initializer functions as
defined by GNU-compatible toolchains. This increases the size
of Zephyr binaries by around 100 bytes. If you know your
application doesn't need any initializers, you can disable this
option.
The ARC MWDT toolchain, does not support or use this setting,
and has instead separate C++ constructor initialization code.
Note the option CMAKE_LINKER_GENERATOR does not yet support this feature
or CPP.
defined by GNU-compatible toolchains. This increases the size of
Zephyr binaries by around 24 bytes. If you know your application
doesn't need any initializers, you can disable this option. The linker
will emit an error if constructors are needed and this option has been
disabled.

endmenu

Expand Down
19 changes: 17 additions & 2 deletions kernel/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,20 @@ static inline int z_vrfy_device_init(const struct device *dev)

extern void boot_banner(void);

#ifdef CONFIG_STATIC_INIT_GNU

extern void (*__zephyr_init_array_start[])();
extern void (*__zephyr_init_array_end[])();

static void z_static_init_gnu(void)
{
void (**fn)();

for (fn = __zephyr_init_array_start; fn != __zephyr_init_array_end; fn++)
(**fn)();
}

#endif

/**
* @brief Mainline for kernel's background thread
Expand Down Expand Up @@ -433,8 +447,9 @@ static void bg_thread_main(void *unused1, void *unused2, void *unused3)
#endif /* CONFIG_STACK_POINTER_RANDOM */
boot_banner();

void z_init_static(void);
z_init_static();
#ifdef CONFIG_STATIC_INIT_GNU
z_static_init_gnu();
#endif /* CONFIG_STATIC_INIT_GNU */

/* Final init level before app starts */
z_sys_init_run_level(INIT_LEVEL_APPLICATION);
Expand Down
87 changes: 0 additions & 87 deletions kernel/init_static.c

This file was deleted.

0 comments on commit 9847555

Please sign in to comment.