1 /* $OpenBSD: tib.c,v 1.3 2022/12/27 17:10:06 jmc Exp $ */
2 /*
3 * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <tib.h>
19
20 #ifndef PIC
21 # include <stdlib.h> /* posix_memalign and free */
22 #endif
23
24 #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1))
25
26
27 /*
28 * The functions here are weak so that the ld.so versions are used
29 * in dynamic links, whether or not libc is static
30 */
31 void *_dl_allocate_tib(size_t _extra) __attribute__((weak));
32 void _dl_free_tib(void *_tib, size_t _extra) __attribute__((weak));
33
34 /*
35 * Allocate a TIB for passing to __tfork for a new thread. 'extra'
36 * is the amount of space to allocate on the side of the TIB opposite
37 * of the TLS data: before the TIB for variant 1 and after the TIB
38 * for variant 2. If non-zero, tib_thread is set to point to that area.
39 */
40 void *
_dl_allocate_tib(size_t extra)41 _dl_allocate_tib(size_t extra)
42 {
43 #ifdef PIC
44 return NULL; /* overridden by ld.so */
45 #else
46 void *base;
47 char *thread;
48
49 # if TLS_VARIANT == 1
50 /* round up the extra size to align the TIB and TLS data after it */
51 extra = (extra <= _static_tls_align_offset) ? 0 :
52 ELF_ROUND(extra - _static_tls_align_offset, _static_tls_align);
53 if (posix_memalign(&base, _static_tls_align, extra +
54 _static_tls_align_offset + sizeof(struct tib) +
55 _static_tls_size) != 0)
56 return NULL;
57 thread = base;
58 base = (char *)base + extra;
59
60 # elif TLS_VARIANT == 2
61 /* round up the TIB size to align the extra area after it */
62 if (posix_memalign(&base, _static_tls_align,
63 _static_tls_align_offset + _static_tls_size +
64 ELF_ROUND(sizeof(struct tib), TIB_EXTRA_ALIGN) + extra) != 0)
65 return NULL;
66 thread = (char *)base + _static_tls_align_offset + _static_tls_size +
67 ELF_ROUND(sizeof(struct tib), TIB_EXTRA_ALIGN);
68 # endif
69
70 return _static_tls_init(base, thread);
71 #endif /* !PIC */
72 }
73
74 void
_dl_free_tib(void * tib,size_t extra)75 _dl_free_tib(void *tib, size_t extra)
76 {
77 #ifndef PIC
78 size_t tib_offset;
79
80 # if TLS_VARIANT == 1
81 tib_offset = (extra <= _static_tls_align_offset) ? 0 :
82 ELF_ROUND(extra - _static_tls_align_offset, _static_tls_align);
83 # elif TLS_VARIANT == 2
84 tib_offset = _static_tls_size;
85 # endif
86 tib_offset += _static_tls_align_offset;
87
88 free((char *)tib - tib_offset);
89 #endif /* !PIC */
90 }
91