-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
kernel: Unify and simplify constructor support #74700
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,63 @@ | ||
/* SPDX-License-Identifier: Apache-2.0 */ | ||
|
||
#ifdef CONFIG_STATIC_INIT_GNU | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Continuing with the previous comment) diff --git a/Kconfig.zephyr b/Kconfig.zephyr
index 9f3e937f849..0e5c665b21d 100644
--- a/Kconfig.zephyr
+++ b/Kconfig.zephyr
@@ -434,7 +434,6 @@ config CODING_GUIDELINE_CHECK
config NATIVE_LIBC
bool
select FULL_LIBC_SUPPORTED
- select STATIC_INIT_GNU
help
Zephyr will use the host system C library.
diff --git a/include/zephyr/linker/common-rom/common-rom-init.ld b/include/zephyr/linker/common-rom/common-rom-init.ld
index 5523882a109..80587af1d1b 100644
--- a/include/zephyr/linker/common-rom/common-rom-init.ld
+++ b/include/zephyr/linker/common-rom/common-rom-init.ld
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: Apache-2.0 */
-#ifdef CONFIG_TOOLCHAIN_SUPPORTS_STATIC_INIT_GNU
+#ifdef CONFIG_STATIC_INIT_GNU
SECTION_PROLOGUE(init_array,,)
{
/*
@@ -14,36 +14,19 @@
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).
- */
- __CTOR_LIST__ = .;
-#ifdef CONFIG_64BIT
- QUAD(0)
- QUAD(0)
-#else
- LONG(0)
- LONG(0)
-#endif
- __CTOR_END__ = .;
-#endif
- /*
- * 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 = .;
} 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
+#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 Note I don't think we need anymore the code that creates the empty lists for native_posix There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I need to switch from the Zephyr names to native C library names and then always include constructors when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think we need to. Why do you say that?
If we do that, won't we be reintroducing #75407 or the counter bug? A bit more background: When we build for native simulator targets (NATIVE_LIBRARY), the Zephyr/embedded SW side of things goes first thru a partial linking on its own without the host C library. There we create Zephyr's constructor list which we will go thru at Zephyr init. For native_posix like targets (NATIVE_APPLICATION), we do the linking of Zephyr, with the "runner", with the host C library and any other host libraries, in one step. Here the Zephyr linker script expands the host linker script (so a Linux compliant constructor list will be built by the host linker script by default) That all being said as native_posix and NATIVE_APPLICATION is being deprecated, I think we can just keep that behavior for NATIVE_APPLICATION by now. And for NATIVE_LIBRARY we can just behave exactly like for embedded targets. No need to treat it differently even if the embedded code will be eventually linked with the host C library. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, so the only place we need to worry about mixing native and Zephyr initializers is with NATIVE_APPLICATION? And that's because there's only a single linker stage? I assume Zephyr is still generating the linker script for that? If so, will that script need to generate a native-compatible initializer list? Which format should it use? Presumably "both", using the old style (count + inits + null) for .ctors and the new style (inits) for .init_array? If all of my assumptions are correct, then the current patch is nearly correct; it just needs to have the selection between Zephyr and Native intializers corrected so that Native initializers are used with NATIVE_APPLICATION and otherwise we always get Zephyr initializers? In any case, we'll still need help from someone who understands MetaWare to make sure we can use the same initializers as all other toolchains. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yep & yep
Partly. In this case Zephyr's linker script is an extension to the default host linker script (see below).
Not necessarily. If for that case we do nothing with .ctors & .init_array's, the host linker script will still generate a fully correct list for the host executable init. Meaning, for NATIVE_APPLICATION, if we do nothing for .ctors in the Zephyr linked script, and do not build in the constructor initialization, the host linker script will still build a correct list, and during the executable init it will be run thru. Just for reference, this is the relevant part of the host linker script in my case:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@evgeniy-paltsev is doing some tests to see if the PR works or not. But even if it works 'today', it may break later if MetaWare changes internal structures and/or C/C++ runtime libs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's unclear how MetaWare could even break things -- none of the Zephyr initializer code is something the toolchain has influence in, except for the ELF sections assigned to the initializer addresses (currently either In any case, the tests included in this PR should catch any toolchain changes in how initializers are handled by the compiler, so if they work today (and the tests pass), we can be reasonably confident that future changes will not pass unnoticed and Zephyr can adapt as needed. Which isn't really any different from handling toolchain changes anywhere else in the system. |
||
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. 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 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. 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) | ||
__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 sybmols, 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 = .; | ||
#endif | ||
#endif | ||
} 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) | ||
#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 | ||
|
||
ASSERT (SIZEOF(init_array) == 0, | ||
"GNU-style constructors required but STATIC_INIT_GNU not enabled") | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,7 +55,6 @@ list(APPEND kernel_files | |
errno.c | ||
fatal.c | ||
init.c | ||
init_static.c | ||
kheap.c | ||
mem_slab.c | ||
float.c | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -403,6 +403,20 @@ | |||
|
||||
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)(); | ||||
} | ||||
Check notice on line 417 in kernel/init.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||||
|
||||
#endif | ||||
|
||||
/** | ||||
* @brief Mainline for kernel's background thread | ||||
|
@@ -433,8 +447,9 @@ | |||
#endif /* CONFIG_STACK_POINTER_RANDOM */ | ||||
boot_banner(); | ||||
|
||||
void z_init_static(void); | ||||
z_init_static(); | ||||
#ifdef CONFIG_STATIC_INIT_GNU | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be removing support for constructors for the arc mwdt toolchain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That seems bad. I'm really unclear as to how those constructors differ from the GNU constructors and whether we can support all of them in a single chunk of linker script. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For MWDT we just call internal Line 27 in e5c05da
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So MWDT places all constructors in .ctors sections, just like some GCC architectures (most GCC targets now use .init_array for "reasons", I assume). I'm not seeing any incompatibility between MWDT and GCC here; we can just collect all of the .ctors and .init_array sections together into one giant array of initialization functions and call them in the right order. That should make everything the same, eliminating any MWDT specific bits. The current v2/linker.ld script places the .ctors sections between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've pushed a separate patch in this PR which removes the special case for MWDT toolchains; I'd appreciate help understanding if this is correct or not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I guess to whatever that toolchain provided There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The MetaWare There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yup, we figured that out yesterday :-). So, #74682 will be merged for 3.7 with just the fixes required to fix the bug. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Unless MWDT is different from the generic GNU version currently though -- it uses This PR makes the GNU code match the MWDT code, removing the leading count and trailing NULL for the .ctors section.
From what I can see, the MWDT compiler places all C++ constructor addresses in Reading through the ARC libgcc code leaves me with some questions though: In that code, destructors are run in forward order while constructors are run in reverse order. All other systems run constructors in forward order (and destructors in reverse order). |
||||
z_static_init_gnu(); | ||||
#endif /* CONFIG_STATIC_INIT_GNU */ | ||||
|
||||
/* Final init level before app starts */ | ||||
z_sys_init_run_level(INIT_LEVEL_APPLICATION); | ||||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would really like to have the arc guys (@evgeniy-paltsev @ruuddw ) confirm things keep working fine for this toolchain. I'm inclined to set a "dnm" until they do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, my first intuition is that this should remain for MetaWare - but need to check with our toolchain or other people that know more about this. I expect the _fctors/_ectors are required for the MetaWare runtime library to handle the constructors/destructors. Not sure that can be replaced by other Zephyr initialization code without other consequences/side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I think that's the best plan -- I think this should work correctly even on MetaWare as we're completely replacing the whole constructor path with Zephyr-specific code, effectively bypassing the MetaWare runtime. But, as you say, we need to have the arc people review this before merging.