From 130fca173f323a24b41873b6656ab77c7cff86e1 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 21 Apr 2021 19:49:50 +0200 Subject: [PATCH] csu: Move calling main out of __libc_start_main_impl This code depends on whether glibc has unwinding support for a particular port. Reviewed-by: Adhemerval Zanella --- csu/libc-start.c | 74 ++-------------------------- sysdeps/generic/libc_start_call_main.h | 24 ++++++++++ sysdeps/nptl/libc_start_call_main.h | 88 ++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 70 deletions(-) create mode 100644 sysdeps/generic/libc_start_call_main.h create mode 100644 sysdeps/nptl/libc_start_call_main.h diff --git a/csu/libc-start.c b/csu/libc-start.c index 05ff7af..8688cba 100644 --- a/csu/libc-start.c +++ b/csu/libc-start.c @@ -58,12 +58,6 @@ uintptr_t __pointer_chk_guard_local # endif #endif -#ifdef HAVE_PTR_NTHREADS -/* We need atomic operations. */ -# include -#endif - - #ifndef SHARED # include # include @@ -123,6 +117,9 @@ apply_irel (void) # define ARCH_INIT_CPU_FEATURES() #endif +/* Obtain the definition of __libc_start_call_main. */ +#include + #ifdef SHARED /* Initialization for dynamic executables. Find the main executable link map and run its init functions. */ @@ -245,9 +242,6 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), void (*fini) (void), void (*rtld_fini) (void), void *stack_end) { - /* Result of the 'main' function. */ - int result; - #ifndef SHARED char **ev = &argv[argc + 1]; @@ -413,68 +407,8 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), #ifndef SHARED _dl_debug_initialize (0, LM_ID_BASE); #endif -#ifdef HAVE_CLEANUP_JMP_BUF - /* Memory for the cancellation buffer. */ - struct pthread_unwind_buf unwind_buf; - - int not_first_call; - DIAG_PUSH_NEEDS_COMMENT; -#if __GNUC_PREREQ (7, 0) - /* This call results in a -Wstringop-overflow warning because struct - pthread_unwind_buf is smaller than jmp_buf. setjmp and longjmp - do not use anything beyond the common prefix (they never access - the saved signal mask), so that is a false positive. */ - DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overflow="); -#endif - not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); - DIAG_POP_NEEDS_COMMENT; - if (__glibc_likely (! not_first_call)) - { - struct pthread *self = THREAD_SELF; - - /* Store old info. */ - unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); - unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); - - /* Store the new cleanup handler info. */ - THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); - - /* Run the program. */ - result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); - } - else - { - /* Remove the thread-local data. */ -# ifdef SHARED - PTHFCT_CALL (ptr__nptl_deallocate_tsd, ()); -# else - extern void __nptl_deallocate_tsd (void) __attribute ((weak)); - __nptl_deallocate_tsd (); -# endif - - /* One less thread. Decrement the counter. If it is zero we - terminate the entire process. */ - result = 0; -# ifdef SHARED - unsigned int *ptr = __libc_pthread_functions.ptr_nthreads; -# ifdef PTR_DEMANGLE - PTR_DEMANGLE (ptr); -# endif -# else - extern unsigned int __nptl_nthreads __attribute ((weak)); - unsigned int *const ptr = &__nptl_nthreads; -# endif - - if (! atomic_decrement_and_test (ptr)) - /* Not much left to do but to exit the thread, not the process. */ - __exit_thread (); - } -#else - /* Nothing fancy, just call the function. */ - result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); -#endif - exit (result); + __libc_start_call_main (main, argc, argv MAIN_AUXVEC_PARAM); } /* Starting with glibc 2.34, the init parameter is always NULL. Older diff --git a/sysdeps/generic/libc_start_call_main.h b/sysdeps/generic/libc_start_call_main.h new file mode 100644 index 0000000..8a06eec --- /dev/null +++ b/sysdeps/generic/libc_start_call_main.h @@ -0,0 +1,24 @@ +/* Invoking main from __libc_start. Generic version without unwinding. + Copyright (C) 1998-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +_Noreturn static __always_inline void +__libc_start_call_main (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + int argc, char **argv MAIN_AUXVEC_DECL) +{ + exit (main (argc, argv, __environ MAIN_AUXVEC_PARAM)); +} diff --git a/sysdeps/nptl/libc_start_call_main.h b/sysdeps/nptl/libc_start_call_main.h new file mode 100644 index 0000000..5218e7a --- /dev/null +++ b/sysdeps/nptl/libc_start_call_main.h @@ -0,0 +1,88 @@ +/* Invoking main from __libc_start_main. nptl version. + Copyright (C) 1998-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +_Noreturn static void +__libc_start_call_main (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + int argc, char **argv +#ifdef LIBC_START_MAIN_AUXVEC_ARG + , ElfW(auxv_t) *auxvec +#endif + ) +{ + int result; + + /* Memory for the cancellation buffer. */ + struct pthread_unwind_buf unwind_buf; + + int not_first_call; + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* This call results in a -Wstringop-overflow warning because struct + pthread_unwind_buf is smaller than jmp_buf. setjmp and longjmp + do not use anything beyond the common prefix (they never access + the saved signal mask), so that is a false positive. */ + DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overflow="); +#endif + not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf); + DIAG_POP_NEEDS_COMMENT; + if (__glibc_likely (! not_first_call)) + { + struct pthread *self = THREAD_SELF; + + /* Store old info. */ + unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); + unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup); + + /* Store the new cleanup handler info. */ + THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf); + + /* Run the program. */ + result = main (argc, argv, __environ MAIN_AUXVEC_PARAM); + } + else + { + /* Remove the thread-local data. */ +# ifdef SHARED + PTHFCT_CALL (ptr__nptl_deallocate_tsd, ()); +# else + extern void __nptl_deallocate_tsd (void) __attribute ((weak)); + __nptl_deallocate_tsd (); +# endif + + /* One less thread. Decrement the counter. If it is zero we + terminate the entire process. */ + result = 0; +# ifdef SHARED + unsigned int *ptr = __libc_pthread_functions.ptr_nthreads; +# ifdef PTR_DEMANGLE + PTR_DEMANGLE (ptr); +# endif +# else + extern unsigned int __nptl_nthreads __attribute ((weak)); + unsigned int *const ptr = &__nptl_nthreads; +# endif + + if (! atomic_decrement_and_test (ptr)) + /* Not much left to do but to exit the thread, not the process. */ + __exit_thread (); + } + + exit (result); +} -- 2.7.4