Re: [RFC PATCH v2 02/10] tools/nolibc: crt: Split _start_c() into stack-only and normal parts
From: Thomas Weißschuh
Date: Mon Feb 16 2026 - 15:42:56 EST
On 2026-02-04 21:45:34+0900, Daniel Palmer wrote:
> To prepare for nolibc programs being able to relocate themselves
> we need to split _start_c() into two parts:
>
> - One part that only uses the stack so there are no accesses via
> the GOT etc that isn't setup yet. Note that on m68k at least
> this also means forcing the stackprotector off because accessing
> the stack protector canary is done via the GOT.
>
> - Another part that is called after we have done relocation so it
> is safe to access global variables etc that might use the GOT etc.
>
> Signed-off-by: Daniel Palmer <daniel@xxxxxxxxx>
> ---
> tools/include/nolibc/compiler.h | 6 ++++
> tools/include/nolibc/crt.h | 57 ++++++++++++++++++---------------
> 2 files changed, 38 insertions(+), 25 deletions(-)
>
> diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h
> index 87090bbc53e0..3f403e54e4f4 100644
> --- a/tools/include/nolibc/compiler.h
> +++ b/tools/include/nolibc/compiler.h
> @@ -47,4 +47,10 @@
> # define __nolibc_fallthrough do { } while (0)
> #endif /* __nolibc_has_attribute(fallthrough) */
>
> +#if __nolibc_has_feature(undefined_behavior_sanitizer)
> +# define __no_sanitize __attribute__((no_sanitize("function")))
> +#else
> +# define __no_sanitize
> +#endif
> +
> #endif /* _NOLIBC_COMPILER_H */
> diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h
> index d9262998dae9..fab042f1ff62 100644
> --- a/tools/include/nolibc/crt.h
> +++ b/tools/include/nolibc/crt.h
> @@ -27,26 +27,45 @@ extern void (*const __init_array_end[])(int, char **, char**) __attribute__((wea
> extern void (*const __fini_array_start[])(void) __attribute__((weak));
> extern void (*const __fini_array_end[])(void) __attribute__((weak));
>
> -void _start_c(long *sp);
> -__attribute__((weak,used))
> -#if __nolibc_has_feature(undefined_behavior_sanitizer)
> - __attribute__((no_sanitize("function")))
> -#endif
> -void _start_c(long *sp)
> +void _start_c_global_data(long argc, char **argv, char **envp, const unsigned long *auxv);
> +__attribute__((weak, used))
The compiler can see that this function is used below, so the attribute
'used' can be dropped.
When not building for 'pie' the 'weak' attribute is also not needed.
It should be 'static' so the function can be inlined again.
Theoretically this should also save some bytes. However in my testing it
generates slightly larger code. So I'm not sure what to do here.
> +void __no_sanitize __no_stack_protector _start_c_global_data(long argc, char **argv, char **envp, const unsigned long *auxv)
> {
(...)
> +}
> +
> +void _start_c(long *sp);
> +__attribute__((weak, used))
> +void __no_sanitize __no_stack_protector _start_c(long *sp)
> +{
(...)
> + _start_c_global_data(argc, argv, envp, auxv);
> }
>
> #endif /* NOLIBC_NO_RUNTIME */
> --
> 2.51.0
>