hppa: Always enable PIE on 64-bit target
[official-gcc.git] / libgcc / emutls.c
blob2313d0a3153926e082568beaa08f32243b3ca49e
1 /* TLS emulation.
2 Copyright (C) 2006-2024 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>.
5 This file is part of GCC.
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.
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.
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.
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/>. */
26 #include "tconfig.h"
27 #include "tsystem.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "libgcc_tm.h"
31 #include "gthr.h"
33 typedef unsigned int word __attribute__((mode(word)));
34 typedef unsigned int pointer __attribute__((mode(pointer)));
36 struct __emutls_object
38 word size;
39 word align;
40 union {
41 pointer offset;
42 void *ptr;
43 } loc;
44 void *templ;
47 struct __emutls_array
49 pointer size;
50 void **data[];
53 /* EMUTLS_ATTR is provided to allow targets to build the emulated tls
54 routines as weak definitions, for example.
55 If there is no definition, fall back to the default. */
56 #ifndef EMUTLS_ATTR
57 # define EMUTLS_ATTR
58 #endif
60 /* __emutls_get_address and __emutls_register_common are registered as
61 builtins, but the compiler struct __emutls_object doesn't have
62 a union in there and is only created when actually needed for
63 the calls to the builtins, so the builtins are created with void *
64 arguments rather than struct __emutls_object *. Avoid
65 -Wbuiltin-declaration-mismatch warnings. */
66 #pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
68 EMUTLS_ATTR
69 void *__emutls_get_address (struct __emutls_object *);
70 EMUTLS_ATTR
71 void __emutls_register_common (struct __emutls_object *, word, word, void *);
73 #ifdef __GTHREADS
74 #ifdef __GTHREAD_MUTEX_INIT
75 static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
76 #else
77 static __gthread_mutex_t emutls_mutex;
78 #endif
79 static __gthread_key_t emutls_key;
80 static pointer emutls_size;
82 static void
83 emutls_destroy (void *ptr)
85 struct __emutls_array *arr = ptr;
86 pointer size = arr->size;
87 pointer i;
89 for (i = 0; i < size; ++i)
91 if (arr->data[i])
92 free (arr->data[i][-1]);
95 free (ptr);
98 static void
99 emutls_init (void)
101 #ifndef __GTHREAD_MUTEX_INIT
102 __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
103 #endif
104 if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
105 abort ();
107 #endif
109 static void *
110 emutls_alloc (struct __emutls_object *obj)
112 void *ptr;
113 void *ret;
115 /* We could use here posix_memalign if available and adjust
116 emutls_destroy accordingly. */
117 if (obj->align <= sizeof (void *))
119 ptr = malloc (obj->size + sizeof (void *));
120 if (ptr == NULL)
121 abort ();
122 ((void **) ptr)[0] = ptr;
123 ret = ptr + sizeof (void *);
125 else
127 ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
128 if (ptr == NULL)
129 abort ();
130 ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
131 & ~(pointer)(obj->align - 1));
132 ((void **) ret)[-1] = ptr;
135 if (obj->templ)
136 memcpy (ret, obj->templ, obj->size);
137 else
138 memset (ret, 0, obj->size);
140 return ret;
143 /* Despite applying the attribute to the declaration, in this case the mis-
144 match between the builtin's declaration [void * (*)(void *)] and the
145 implementation here, causes the decl. attributes to be discarded. */
147 EMUTLS_ATTR void *
148 __emutls_get_address (struct __emutls_object *obj)
150 if (! __gthread_active_p ())
152 if (__builtin_expect (obj->loc.ptr == NULL, 0))
153 obj->loc.ptr = emutls_alloc (obj);
154 return obj->loc.ptr;
157 #ifndef __GTHREADS
158 abort ();
159 #else
160 pointer offset = __atomic_load_n (&obj->loc.offset, __ATOMIC_ACQUIRE);
162 if (__builtin_expect (offset == 0, 0))
164 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
165 __gthread_once (&once, emutls_init);
166 __gthread_mutex_lock (&emutls_mutex);
167 offset = obj->loc.offset;
168 if (offset == 0)
170 offset = ++emutls_size;
171 __atomic_store_n (&obj->loc.offset, offset, __ATOMIC_RELEASE);
173 __gthread_mutex_unlock (&emutls_mutex);
176 struct __emutls_array *arr = __gthread_getspecific (emutls_key);
177 if (__builtin_expect (arr == NULL, 0))
179 pointer size = offset + 32;
180 arr = calloc (size + 1, sizeof (void *));
181 if (arr == NULL)
182 abort ();
183 arr->size = size;
184 __gthread_setspecific (emutls_key, (void *) arr);
186 else if (__builtin_expect (offset > arr->size, 0))
188 pointer orig_size = arr->size;
189 pointer size = orig_size * 2;
190 if (offset > size)
191 size = offset + 32;
192 arr = realloc (arr, (size + 1) * sizeof (void *));
193 if (arr == NULL)
194 abort ();
195 arr->size = size;
196 memset (arr->data + orig_size, 0,
197 (size - orig_size) * sizeof (void *));
198 __gthread_setspecific (emutls_key, (void *) arr);
201 void *ret = arr->data[offset - 1];
202 if (__builtin_expect (ret == NULL, 0))
204 ret = emutls_alloc (obj);
205 arr->data[offset - 1] = ret;
207 return ret;
208 #endif
211 EMUTLS_ATTR void
212 __emutls_register_common (struct __emutls_object *obj,
213 word size, word align, void *templ)
215 if (obj->size < size)
217 obj->size = size;
218 obj->templ = NULL;
220 if (obj->align < align)
221 obj->align = align;
222 if (templ && size == obj->size)
223 obj->templ = templ;