1 /* Thread library support for -fsplit-stack. */ 2 /* Copyright (C) 2009-2022 Free Software Foundation, Inc. 3 Contributed by Ian Lance Taylor <iant@google.com>. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it under 8 the terms of the GNU General Public License as published by the Free 9 Software Foundation; either version 3, or (at your option) any later 10 version. 11 12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 Under Section 7 of GPL version 3, you are granted additional 18 permissions described in the GCC Runtime Library Exception, version 19 3.1, as published by the Free Software Foundation. 20 21 You should have received a copy of the GNU General Public License and 22 a copy of the GCC Runtime Library Exception along with this program; 23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 <http://www.gnu.org/licenses/>. */ 25 26 #include "tconfig.h" 27 #include "tsystem.h" 28 #include "coretypes.h" 29 #include "tm.h" 30 #include "libgcc_tm.h" 31 32 /* If inhibit_libc is defined, we cannot compile this file. The 33 effect is that people will not be able to use -fsplit-stack. That 34 is much better than failing the build particularly since people 35 will want to define inhibit_libc while building a compiler which 36 can build glibc. */ 37 38 #ifndef inhibit_libc 39 40 #include <errno.h> 41 #include <signal.h> 42 #include <pthread.h> 43 44 #include "generic-morestack.h" 45 46 /* We declare the pthread functions we need as weak, so that 47 libgcc_s.so does not need to be linked against -lpthread. */ 48 49 extern int pthread_once (pthread_once_t *, void (*) (void)) 50 __attribute__ ((weak)); 51 52 extern int pthread_key_create (pthread_key_t *, void (*) (void *)) 53 __attribute__ ((weak)); 54 55 extern int pthread_setspecific (pthread_key_t, const void *) 56 __attribute__ ((weak)); 57 58 extern int pthread_sigmask (int, const sigset_t *, sigset_t *) 59 __attribute__ ((weak)); 60 61 /* The key for the list of stack segments to free when the thread 62 exits. This is created by pthread_key_create. */ 63 64 static pthread_key_t segment_list_key; 65 66 /* Used to only run create_key once. */ 67 68 static pthread_once_t create_key_once = PTHREAD_ONCE_INIT; 69 70 /* Release all the segments for a thread. This is the destructor 71 function used by pthread_key_create, and is called when a thread 72 exits. */ 73 74 static void 75 free_segments (void* arg) 76 { 77 /* We must block signals in case the signal handler tries to split 78 the stack. We leave them blocked while the thread exits. */ 79 if (pthread_sigmask) 80 { 81 sigset_t mask; 82 83 sigfillset (&mask); 84 pthread_sigmask (SIG_BLOCK, &mask, NULL); 85 } 86 87 __morestack_release_segments ((struct stack_segment **) arg, 1); 88 } 89 90 /* Set up the key for the list of segments. This is called via 91 pthread_once. */ 92 93 static void 94 create_key (void) 95 { 96 int err; 97 98 err = pthread_key_create (&segment_list_key, free_segments); 99 if (err != 0) 100 { 101 static const char msg[] = "pthread_key_create failed: errno "; 102 __morestack_fail (msg, sizeof msg - 1, err); 103 } 104 } 105 106 /* Pass information from the pthread_create wrapper to 107 stack_split_initialize_thread. */ 108 109 struct pthread_create_args 110 { 111 void *(*start_routine) (void *); 112 void *arg; 113 }; 114 115 /* Initialize a thread. This is called via pthread_create. It calls 116 a target dependent function to set up any required stack guard. */ 117 118 static void* stack_split_initialize_thread (void *) 119 __attribute__ ((no_split_stack)); 120 121 static void * 122 stack_split_initialize_thread (void *varg) 123 { 124 struct pthread_create_args *args = (struct pthread_create_args *) varg; 125 int err; 126 void *(*start_routine) (void *); 127 void *arg; 128 129 __stack_split_initialize (); 130 131 err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments); 132 if (err != 0) 133 { 134 static const char msg[] = "pthread_setspecific failed: errno "; 135 __morestack_fail (msg, sizeof msg - 1, err); 136 } 137 138 start_routine = args->start_routine; 139 arg = args->arg; 140 free (args); 141 return (*start_routine) (arg); 142 } 143 144 /* This function wraps calls to pthread_create to make sure that the 145 stack guard is initialized for new threads. FIXME: This hack will 146 not be necessary if glibc supports -fsplit-stack directly. */ 147 148 int __wrap_pthread_create (pthread_t *, const pthread_attr_t *, 149 void *(*start_routine) (void *), void *) 150 __attribute__ ((visibility ("hidden"))); 151 152 extern int __real_pthread_create (pthread_t *, const pthread_attr_t *, 153 void *(*start_routine) (void *), void *) 154 __attribute__ ((weak)); 155 156 int 157 __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr, 158 void *(*start_routine) (void *), void *arg) 159 { 160 int err; 161 struct pthread_create_args* args; 162 163 err = pthread_once (&create_key_once, create_key); 164 if (err != 0) 165 { 166 static const char msg[] = "pthread_once failed: errno "; 167 __morestack_fail (msg, sizeof msg - 1, err); 168 } 169 170 args = malloc (sizeof (struct pthread_create_args)); 171 if (args == NULL) 172 return EAGAIN; 173 args->start_routine = start_routine; 174 args->arg = arg; 175 return __real_pthread_create (tid, attr, stack_split_initialize_thread, args); 176 } 177 178 #endif /* !defined (inhibit_libc) */ 179