11debfc3dSmrg /* Thread library support for -fsplit-stack. */
2*8feb0f0bSmrg /* Copyright (C) 2009-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Ian Lance Taylor <iant@google.com>.
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
81debfc3dSmrg the terms of the GNU General Public License as published by the Free
91debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
101debfc3dSmrg version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
131debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
141debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151debfc3dSmrg for more details.
161debfc3dSmrg
171debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
181debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
191debfc3dSmrg 3.1, as published by the Free Software Foundation.
201debfc3dSmrg
211debfc3dSmrg You should have received a copy of the GNU General Public License and
221debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
231debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
241debfc3dSmrg <http://www.gnu.org/licenses/>. */
251debfc3dSmrg
261debfc3dSmrg #include "tconfig.h"
271debfc3dSmrg #include "tsystem.h"
281debfc3dSmrg #include "coretypes.h"
291debfc3dSmrg #include "tm.h"
301debfc3dSmrg #include "libgcc_tm.h"
311debfc3dSmrg
321debfc3dSmrg /* If inhibit_libc is defined, we cannot compile this file. The
331debfc3dSmrg effect is that people will not be able to use -fsplit-stack. That
341debfc3dSmrg is much better than failing the build particularly since people
351debfc3dSmrg will want to define inhibit_libc while building a compiler which
361debfc3dSmrg can build glibc. */
371debfc3dSmrg
381debfc3dSmrg #ifndef inhibit_libc
391debfc3dSmrg
401debfc3dSmrg #include <errno.h>
411debfc3dSmrg #include <pthread.h>
421debfc3dSmrg
431debfc3dSmrg #include "generic-morestack.h"
441debfc3dSmrg
451debfc3dSmrg /* We declare the pthread functions we need as weak, so that
461debfc3dSmrg libgcc_s.so does not need to be linked against -lpthread. */
471debfc3dSmrg
481debfc3dSmrg extern int pthread_once (pthread_once_t *, void (*) (void))
491debfc3dSmrg __attribute__ ((weak));
501debfc3dSmrg
511debfc3dSmrg extern int pthread_key_create (pthread_key_t *, void (*) (void *))
521debfc3dSmrg __attribute__ ((weak));
531debfc3dSmrg
541debfc3dSmrg extern int pthread_setspecific (pthread_key_t, const void *)
551debfc3dSmrg __attribute__ ((weak));
561debfc3dSmrg
571debfc3dSmrg /* The key for the list of stack segments to free when the thread
581debfc3dSmrg exits. This is created by pthread_key_create. */
591debfc3dSmrg
601debfc3dSmrg static pthread_key_t segment_list_key;
611debfc3dSmrg
621debfc3dSmrg /* Used to only run create_key once. */
631debfc3dSmrg
641debfc3dSmrg static pthread_once_t create_key_once = PTHREAD_ONCE_INIT;
651debfc3dSmrg
661debfc3dSmrg /* Release all the segments for a thread. This is the destructor
671debfc3dSmrg function used by pthread_key_create, and is called when a thread
681debfc3dSmrg exits. */
691debfc3dSmrg
701debfc3dSmrg static void
free_segments(void * arg)711debfc3dSmrg free_segments (void* arg)
721debfc3dSmrg {
731debfc3dSmrg __morestack_release_segments ((struct stack_segment **) arg, 1);
741debfc3dSmrg }
751debfc3dSmrg
761debfc3dSmrg /* Set up the key for the list of segments. This is called via
771debfc3dSmrg pthread_once. */
781debfc3dSmrg
791debfc3dSmrg static void
create_key(void)801debfc3dSmrg create_key (void)
811debfc3dSmrg {
821debfc3dSmrg int err;
831debfc3dSmrg
841debfc3dSmrg err = pthread_key_create (&segment_list_key, free_segments);
851debfc3dSmrg if (err != 0)
861debfc3dSmrg {
871debfc3dSmrg static const char msg[] = "pthread_key_create failed: errno ";
881debfc3dSmrg __morestack_fail (msg, sizeof msg - 1, err);
891debfc3dSmrg }
901debfc3dSmrg }
911debfc3dSmrg
921debfc3dSmrg /* Pass information from the pthread_create wrapper to
931debfc3dSmrg stack_split_initialize_thread. */
941debfc3dSmrg
951debfc3dSmrg struct pthread_create_args
961debfc3dSmrg {
971debfc3dSmrg void *(*start_routine) (void *);
981debfc3dSmrg void *arg;
991debfc3dSmrg };
1001debfc3dSmrg
1011debfc3dSmrg /* Initialize a thread. This is called via pthread_create. It calls
1021debfc3dSmrg a target dependent function to set up any required stack guard. */
1031debfc3dSmrg
1041debfc3dSmrg static void* stack_split_initialize_thread (void *)
1051debfc3dSmrg __attribute__ ((no_split_stack));
1061debfc3dSmrg
1071debfc3dSmrg static void *
stack_split_initialize_thread(void * varg)1081debfc3dSmrg stack_split_initialize_thread (void *varg)
1091debfc3dSmrg {
1101debfc3dSmrg struct pthread_create_args *args = (struct pthread_create_args *) varg;
1111debfc3dSmrg int err;
1121debfc3dSmrg void *(*start_routine) (void *);
1131debfc3dSmrg void *arg;
1141debfc3dSmrg
1151debfc3dSmrg __stack_split_initialize ();
1161debfc3dSmrg
1171debfc3dSmrg err = pthread_setspecific (segment_list_key, (void *) &__morestack_segments);
1181debfc3dSmrg if (err != 0)
1191debfc3dSmrg {
1201debfc3dSmrg static const char msg[] = "pthread_setspecific failed: errno ";
1211debfc3dSmrg __morestack_fail (msg, sizeof msg - 1, err);
1221debfc3dSmrg }
1231debfc3dSmrg
1241debfc3dSmrg start_routine = args->start_routine;
1251debfc3dSmrg arg = args->arg;
1261debfc3dSmrg free (args);
1271debfc3dSmrg return (*start_routine) (arg);
1281debfc3dSmrg }
1291debfc3dSmrg
1301debfc3dSmrg /* This function wraps calls to pthread_create to make sure that the
1311debfc3dSmrg stack guard is initialized for new threads. FIXME: This hack will
1321debfc3dSmrg not be necessary if glibc supports -fsplit-stack directly. */
1331debfc3dSmrg
1341debfc3dSmrg int __wrap_pthread_create (pthread_t *, const pthread_attr_t *,
1351debfc3dSmrg void *(*start_routine) (void *), void *)
1361debfc3dSmrg __attribute__ ((visibility ("hidden")));
1371debfc3dSmrg
1381debfc3dSmrg extern int __real_pthread_create (pthread_t *, const pthread_attr_t *,
1391debfc3dSmrg void *(*start_routine) (void *), void *)
1401debfc3dSmrg __attribute__ ((weak));
1411debfc3dSmrg
1421debfc3dSmrg int
__wrap_pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)1431debfc3dSmrg __wrap_pthread_create (pthread_t *tid, const pthread_attr_t *attr,
1441debfc3dSmrg void *(*start_routine) (void *), void *arg)
1451debfc3dSmrg {
1461debfc3dSmrg int err;
1471debfc3dSmrg struct pthread_create_args* args;
1481debfc3dSmrg
1491debfc3dSmrg err = pthread_once (&create_key_once, create_key);
1501debfc3dSmrg if (err != 0)
1511debfc3dSmrg {
1521debfc3dSmrg static const char msg[] = "pthread_once failed: errno ";
1531debfc3dSmrg __morestack_fail (msg, sizeof msg - 1, err);
1541debfc3dSmrg }
1551debfc3dSmrg
1561debfc3dSmrg args = malloc (sizeof (struct pthread_create_args));
1571debfc3dSmrg if (args == NULL)
1581debfc3dSmrg return EAGAIN;
1591debfc3dSmrg args->start_routine = start_routine;
1601debfc3dSmrg args->arg = arg;
1611debfc3dSmrg return __real_pthread_create (tid, attr, stack_split_initialize_thread, args);
1621debfc3dSmrg }
1631debfc3dSmrg
1641debfc3dSmrg #endif /* !defined (inhibit_libc) */
165