xref: /openbsd-src/lib/libc/dlfcn/tib.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: tib.c,v 1.1 2016/05/07 19:05:22 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>		/* malloc 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 	char *base;
47 	char *thread;
48 	struct tib *tib;
49 
50 # if TLS_VARIANT == 1
51 	/* round up the extra size to align the tib after it */
52 	extra = ELF_ROUND(extra, sizeof(void *));
53 	base = malloc(extra + sizeof(struct tib) + _static_tls_size);
54 	tib = (struct tib *)(base + extra);
55 	thread = base;
56 
57 # elif TLS_VARIANT == 2
58 	/* round up the tib size to align the extra area after it */
59 	base = malloc(ELF_ROUND(sizeof(struct tib), TIB_EXTRA_ALIGN) +
60 	    extra + _static_tls_size);
61 	tib = (struct tib *)(base + _static_tls_size);
62 	thread = (char *)tib + ELF_ROUND(sizeof(struct tib), TIB_EXTRA_ALIGN);
63 # endif
64 
65 	_static_tls_init(base);
66 	TIB_INIT(tib, NULL, thread);
67 
68 	return (tib);
69 #endif /* !PIC */
70 }
71 
72 void
73 _dl_free_tib(void *tib, size_t extra)
74 {
75 #ifndef PIC
76 	size_t tib_offset;
77 
78 # if TLS_VARIANT == 1
79 	tib_offset = ELF_ROUND(extra, sizeof(void *));
80 # elif TLS_VARIANT == 2
81 	tib_offset = _static_tls_size;
82 # endif
83 
84 	free((char *)tib - tib_offset);
85 #endif /* !PIC */
86 }
87