xref: /openbsd/lib/libc/dlfcn/tib.c (revision 3cab2bb3)
1 /*	$OpenBSD: tib.c,v 1.2 2017/12/01 23:30:05 guenther 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 *
41 _dl_allocate_tib(size_t extra)
42 {
43 #ifdef PIC
44 	return NULL;			/* overriden 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
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