kernel: Unify .ctors and .init_array handling
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. When building a NATIVE_APPLICATION, we ask the native C library to run all of the constructors to ensure any non-Zephyr constructors are run before main is invoked. It might be "nice" to split the constructors so that the Zephyr constructors were executed by the Zephyr code while the non-Zephyr ones were executed by the native C library. I think that could be done if we knew the pathnames of either the Zephyr or non-Zephyr files. That might make a good future enhancement. Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
cea2487d3d
commit
9398174340
6 changed files with 81 additions and 169 deletions
|
@ -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.
|
||||
|
@ -317,11 +310,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)
|
||||
|
|
|
@ -1,75 +1,65 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef CONFIG_STATIC_INIT_GNU
|
||||
SECTION_PROLOGUE(_CTOR_SECTION_NAME,,)
|
||||
#if defined(CONFIG_TOOLCHAIN_SUPPORTS_STATIC_INIT_GNU) || defined(CONFIG_NATIVE_APPLICATION)
|
||||
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.
|
||||
* Instead, Zephyr's start-up code uses the __ZEPHYR_CTOR_LIST__ and
|
||||
* __ZEHPYR_CTOR_END__ symbols.
|
||||
* 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 we're creating
|
||||
* an init_array style list and leaving the ctors list empty
|
||||
*/
|
||||
#ifdef CONFIG_NATIVE_APPLICATION
|
||||
/* Use the native LIBC constructor code so that any native
|
||||
* constructors get run before main is invoked
|
||||
*/
|
||||
__init_array_start = .;
|
||||
#else
|
||||
__zephyr_init_array_start = .;
|
||||
#endif
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*)
|
||||
SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP (*(.init_array .ctors))
|
||||
#ifdef CONFIG_NATIVE_APPLICATION
|
||||
__init_array_end = .;
|
||||
#else
|
||||
__zephyr_init_array_end = .;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NATIVE_LIBC
|
||||
/*
|
||||
* The __CTOR_LIST__ and __CTOR_END__ symbols are always defined
|
||||
* to result in an empty list.
|
||||
* Instead, Zephyr's start-up code uses the __zephyr_init_array_start__ and
|
||||
* __zephyr_init_array_end__ symbols.
|
||||
* In this way, in native_simulator based targets, the host glibc process
|
||||
* initialization code will not call the constructors before Zephyr loads.
|
||||
*/
|
||||
__CTOR_LIST__ = .;
|
||||
#ifdef CONFIG_64BIT
|
||||
. = ALIGN(8);
|
||||
__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);
|
||||
__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,,)
|
||||
{
|
||||
__CTOR_END__ = .;
|
||||
#ifndef CONFIG_NATIVE_APPLICATION
|
||||
/*
|
||||
* 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 symbols, so these need to be set correctly.
|
||||
*/
|
||||
. = ALIGN(4);
|
||||
* 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.
|
||||
*/
|
||||
__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)
|
||||
|
||||
ASSERT (SIZEOF(init_array) == 0,
|
||||
"GNU-style constructors required but STATIC_INIT_GNU not enabled")
|
||||
#endif
|
||||
#endif
|
||||
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
|
||||
|
||||
#if !defined(CONFIG_STATIC_INIT_GNU) && !defined(CONFIG_NATIVE_APPLICATION)
|
||||
ASSERT(__zephyr_init_array_start == __zephyr_init_array_end,
|
||||
"GNU-style constructors required but STATIC_INIT_GNU not enabled")
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,7 +55,6 @@ list(APPEND kernel_files
|
|||
errno.c
|
||||
fatal.c
|
||||
init.c
|
||||
init_static.c
|
||||
kheap.c
|
||||
mem_slab.c
|
||||
float.c
|
||||
|
|
|
@ -1046,10 +1046,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"
|
||||
|
@ -1059,14 +1059,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.
|
||||
|
||||
config BOOTARGS
|
||||
bool "Support bootargs"
|
||||
|
|
|
@ -483,6 +483,27 @@ static char **prepare_main_args(int *argc)
|
|||
(*argc)++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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++) {
|
||||
/* MWDT toolchain sticks a NULL at the end of the array */
|
||||
if (*fn == NULL) {
|
||||
break;
|
||||
}
|
||||
(**fn)();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -524,8 +545,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);
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2015 Wind River Systems, Inc.
|
||||
* Copyright (c) 2021 Synopsys, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
void __do_global_ctors_aux(void);
|
||||
void __do_init_array_aux(void);
|
||||
|
||||
void z_init_static(void)
|
||||
{
|
||||
#if defined(CONFIG_STATIC_INIT_GNU)
|
||||
__do_global_ctors_aux();
|
||||
__do_init_array_aux();
|
||||
#elif defined(__CCAC__) /* ARC MWDT */
|
||||
__do_global_ctors_aux();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @section - Constructor module
|
||||
* @brief
|
||||
* The ctors section contains a list of function pointers that execute both the C++ constructors of
|
||||
* static global objects, as well as either C or C++ initializer functions (declared with the
|
||||
* attribute constructor). These must be executed before the application's main() routine.
|
||||
*
|
||||
* NOTE: Not all compilers put those function pointers into the ctors section;
|
||||
* some put them into the init_array section instead.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STATIC_INIT_GNU
|
||||
|
||||
/* What a constructor function pointer looks like */
|
||||
|
||||
typedef void (*CtorFuncPtr)(void);
|
||||
|
||||
/* Constructor function pointer list is generated by the linker script. */
|
||||
|
||||
extern CtorFuncPtr __ZEPHYR_CTOR_LIST__[];
|
||||
extern CtorFuncPtr __ZEPHYR_CTOR_END__[];
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Invoke all C++ style global object constructors
|
||||
*
|
||||
* This routine is invoked by the kernel prior to the execution of the
|
||||
* application's main().
|
||||
*/
|
||||
void __do_global_ctors_aux(void)
|
||||
{
|
||||
unsigned int nCtors;
|
||||
|
||||
nCtors = (unsigned long)__ZEPHYR_CTOR_LIST__[0];
|
||||
|
||||
while (nCtors >= 1U) {
|
||||
__ZEPHYR_CTOR_LIST__[nCtors--]();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @section
|
||||
* @brief Execute initialization routines referenced in .init_array section
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STATIC_INIT_GNU
|
||||
|
||||
typedef void (*func_ptr)(void);
|
||||
|
||||
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 = __zephyr_init_array_start;
|
||||
func < __zephyr_init_array_end;
|
||||
func++) {
|
||||
(*func)();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue