1/*
2 * Copyright (c) 2016 Philip Guenther <guenther@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/*
18 * Thread Information Block (TIB) and Thread Local Storage (TLS) handling
19 * (the TCB, Thread Control Block, is part of the TIB)
20 */
21
22#define _DYN_LOADER
23
24#include <sys/types.h>
25
26#include "syscall.h"
27#include "util.h"
28#include "resolve.h"
29
30/* If we need the syscall, use our local syscall definition */
31#define	__set_tcb(tcb)	_dl___set_tcb(tcb)
32
33__dso_hidden void *allocate_tib(size_t);
34
35#ifdef TIB_EXTRA_ALIGN
36# define TIB_ALIGN	MAXIMUM(__alignof__(struct tib), TIB_EXTRA_ALIGN)
37#else
38# define TIB_ALIGN	__alignof__(struct tib)
39#endif
40
41
42/* size of static TLS allocation */
43static int	static_tls_size;
44/* alignment of static TLS allocation */
45static int	static_tls_align;
46/* base-offset alignment of (first) static TLS allocation */
47static int	static_tls_align_offset;
48
49int		_dl_tib_static_done;
50
51/*
52 * Allocate a TIB for passing to __tfork for a new thread.  'extra'
53 * is the amount of space to allocate on the side of the TIB opposite
54 * of the TLS data: before the TIB for variant 1 and after the TIB
55 * for variant 2.  If non-zero, tib_thread is set to point to that area.
56 */
57void *
58allocate_tib(size_t extra)
59{
60	char *base;
61	struct tib *tib;
62	char *thread = NULL;
63	struct elf_object *obj;
64
65#if TLS_VARIANT == 1
66	/* round up the extra size to align the TIB and TLS data after it */
67	size_t unpad_extra = (extra <= static_tls_align_offset) ? 0 :
68	    ELF_ROUND(extra - static_tls_align_offset, static_tls_align);
69	base = _dl_aligned_alloc(static_tls_align, unpad_extra +
70	    static_tls_align_offset + sizeof *tib + static_tls_size);
71	if (base == NULL)
72		return NULL;
73	tib = (struct tib *)(base + unpad_extra + static_tls_align_offset);
74	if (extra)
75		thread = base;
76#define TLS_ADDR(tibp, offset)	((char *)(tibp) + sizeof(struct tib) + (offset))
77
78#elif TLS_VARIANT == 2
79	/* round up the TIB size to align the extra area after it */
80	base = _dl_aligned_alloc(static_tls_align, static_tls_size +
81	    static_tls_align_offset + ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN) +
82	    extra);
83	if (base == NULL)
84		return NULL;
85	base += static_tls_align_offset;
86	tib = (struct tib *)(base + static_tls_size);
87	if (extra)
88		thread = (char *)tib + ELF_ROUND(sizeof *tib, TIB_EXTRA_ALIGN);
89#define TLS_ADDR(tibp, offset)	((char *)(tibp) - (offset))
90
91#endif
92
93	for (obj = _dl_objects; obj != NULL; obj = obj->next) {
94		if (obj->tls_msize != 0) {
95			char *addr = TLS_ADDR(tib, obj->tls_offset);
96
97			_dl_memset(addr + obj->tls_fsize, 0,
98			    obj->tls_msize - obj->tls_fsize);
99			if (obj->tls_static_data != NULL)
100				_dl_bcopy(obj->tls_static_data, addr,
101				    obj->tls_fsize);
102			DL_DEB(("\t%s has index %u addr %p msize %u fsize %u\n",
103				obj->load_name, obj->tls_offset,
104				(void *)addr, obj->tls_msize, obj->tls_fsize));
105		}
106	}
107
108	TIB_INIT(tib, NULL, thread);
109
110	DL_DEB(("tib new=%p\n", (void *)tib));
111
112	return (tib);
113}
114__strong_alias(_dl_allocate_tib, allocate_tib);
115
116void
117_dl_free_tib(void *tib, size_t extra)
118{
119	size_t tib_offset;
120
121#if TLS_VARIANT == 1
122	tib_offset = (extra <= static_tls_align_offset) ? 0 :
123	    ELF_ROUND(extra - static_tls_align_offset, static_tls_align);
124#elif TLS_VARIANT == 2
125	tib_offset = static_tls_size;
126#endif
127	tib_offset += static_tls_align_offset;
128
129	DL_DEB(("free tib=%p\n", (void *)tib));
130	_dl_free((char *)tib - tib_offset);
131}
132
133
134/*
135 * Record what's necessary for handling TLS for an object.
136 */
137void
138_dl_set_tls(elf_object_t *object, Elf_Phdr *ptls, Elf_Addr libaddr,
139    const char *libname)
140{
141	if (ptls->p_vaddr != 0 && ptls->p_filesz != 0)
142		object->tls_static_data = (void *)(ptls->p_vaddr + libaddr);
143	object->tls_fsize = ptls->p_filesz;
144	object->tls_msize = ptls->p_memsz;
145	object->tls_align = ptls->p_align;
146
147	DL_DEB(("tls %x %x %x %x\n",
148	    object->tls_static_data, object->tls_fsize, object->tls_msize,
149	    object->tls_align));
150}
151
152static inline Elf_Addr
153allocate_tls_offset(Elf_Addr msize, Elf_Addr align, int for_exe)
154{
155	Elf_Addr offset;
156
157	if (for_exe && static_tls_size != 0)
158		_dl_die("TLS allocation before executable!");
159
160#if TLS_VARIANT == 1
161	if (for_exe) {
162		/*
163		 * Variant 1 places the data after the TIB.  If the
164		 * TLS alignment is larger than the TIB alignment
165		 * then we may need to pad in front of the TIB to
166		 * place the TLS data on the proper alignment.
167		 * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4
168		 * - need to offset the TIB 12 bytes from the start
169		 * - to place ths TLS data at offset 64
170		 */
171		static_tls_align = MAXIMUM(align, TIB_ALIGN);
172		static_tls_align_offset =
173		    ELF_ROUND(sizeof(struct tib), static_tls_align) -
174		    sizeof(struct tib);
175		offset = 0;
176		static_tls_size = msize;
177	} else {
178		/*
179		 * If a later object increases the alignment, realign the
180		 * existing sections.  We push as much padding as possible
181		 * to the start there it can overlap the thread structure
182		 */
183		if (static_tls_align < align) {
184			static_tls_align_offset += align - static_tls_align;
185			static_tls_align = align;
186		}
187
188		/*
189		 * Round up to the required alignment, taking into account
190		 * the leading padding and TIB, then allocate the space.
191		 */
192		offset = static_tls_align_offset + sizeof(struct tib) +
193		    static_tls_size;
194		offset = ELF_ROUND(offset, align) - static_tls_align_offset
195		    - sizeof(struct tib);
196		static_tls_size = offset + msize;
197	}
198#elif TLS_VARIANT == 2
199	/* Realignment is automatic for variant II */
200	if (static_tls_align < align)
201		static_tls_align = align;
202
203	/*
204	 * Variant 2 places the data before the TIB so we need to round up
205	 * the size to the TLS data alignment TIB's alignment.
206	 * Example A: p_memsz=24 p_align=16 align(TIB)=8
207	 * - need to allocate 32 bytes for TLS as compiler
208	 * - will give the first TLS symbol an offset of -32
209	 * Example B: p_memsz=4 p_align=4 align(TIB)=8
210	 * - need to allocate 8 bytes so that the TIB is
211	 * - properly aligned
212	 * So: allocate the space, then round up to the alignment
213	 * (these are negative offsets, so rounding up really
214	 * rounds the address down)
215	 */
216	static_tls_size = ELF_ROUND(static_tls_size + msize, align);
217	offset = static_tls_size;
218#else
219# error "unknown TLS_VARIANT"
220#endif
221	return offset;
222}
223
224/*
225 * Calculate the TLS offset for each object with static TLS.
226 */
227void
228_dl_allocate_tls_offsets(void)
229{
230	struct elf_object *obj;
231
232	static_tls_align = TIB_ALIGN;
233	for (obj = _dl_objects; obj != NULL; obj = obj->next) {
234		if (obj->tls_msize != 0) {
235			obj->tls_offset = allocate_tls_offset(obj->tls_msize,
236			    obj->tls_align, obj->obj_type == OBJTYPE_EXE);
237		}
238	}
239
240#if TLS_VARIANT == 2
241	static_tls_align_offset = ELF_ROUND(static_tls_size, static_tls_align)
242	    - static_tls_size;
243#endif
244
245	/* no more static TLS allocations after this */
246	_dl_tib_static_done = 1;
247
248	DL_DEB(("static tls size=%x align=%x offset=%x\n",
249	    static_tls_size, static_tls_align, static_tls_align_offset));
250}
251
252/*
253 * Allocate the TIB + TLS for the initial thread.
254 */
255void
256_dl_allocate_first_tib(void)
257{
258	struct tib *tib;
259
260	tib = allocate_tib(0);
261	tib->tib_tid = _dl_getthrid();
262
263	TCB_SET(TIB_TO_TCB(tib));
264}
265