xref: /openbsd/libexec/ld.so/tib.c (revision a4e0416e)
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 */
43 static int	static_tls_size;
44 /* alignment of static TLS allocation */
45 static int	static_tls_align;
46 /* base-offset alignment of (first) static TLS allocation */
47 static int	static_tls_align_offset;
48 
49 int		_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  */
57 void *
allocate_tib(size_t extra)58 allocate_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 
116 void
_dl_free_tib(void * tib,size_t extra)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  */
137 void
_dl_set_tls(elf_object_t * object,Elf_Phdr * ptls,Elf_Addr libaddr,const char * libname)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 
152 static inline Elf_Addr
allocate_tls_offset(Elf_Addr msize,Elf_Addr align,int for_exe)153 allocate_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  */
227 void
_dl_allocate_tls_offsets(void)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  */
255 void
_dl_allocate_first_tib(void)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