xref: /freebsd/libexec/rtld-elf/aarch64/reloc.c (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1 /*-
2  * Copyright (c) 2014-2015 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * Portions of this software were developed by Andrew Turner
6  * under sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 
32 #include <stdlib.h>
33 
34 #include "debug.h"
35 #include "rtld.h"
36 #include "rtld_printf.h"
37 
38 /*
39  * It is possible for the compiler to emit relocations for unaligned data.
40  * We handle this situation with these inlines.
41  */
42 #define	RELOC_ALIGNED_P(x) \
43 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
44 
45 /*
46  * This is not the correct prototype, but we only need it for
47  * a function pointer to a simple asm function.
48  */
49 void *_rtld_tlsdesc_static(void *);
50 void *_rtld_tlsdesc_undef(void *);
51 void *_rtld_tlsdesc_dynamic(void *);
52 
53 void _exit(int);
54 
55 void
56 init_pltgot(Obj_Entry *obj)
57 {
58 
59 	if (obj->pltgot != NULL) {
60 		obj->pltgot[1] = (Elf_Addr) obj;
61 		obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
62 	}
63 }
64 
65 int
66 do_copy_relocations(Obj_Entry *dstobj)
67 {
68 	const Obj_Entry *srcobj, *defobj;
69 	const Elf_Rela *relalim;
70 	const Elf_Rela *rela;
71 	const Elf_Sym *srcsym;
72 	const Elf_Sym *dstsym;
73 	const void *srcaddr;
74 	const char *name;
75 	void *dstaddr;
76 	SymLook req;
77 	size_t size;
78 	int res;
79 
80 	/*
81 	 * COPY relocs are invalid outside of the main program
82 	 */
83 	assert(dstobj->mainprog);
84 
85 	relalim = (const Elf_Rela *)((const char *)dstobj->rela +
86 	    dstobj->relasize);
87 	for (rela = dstobj->rela; rela < relalim; rela++) {
88 		if (ELF_R_TYPE(rela->r_info) != R_AARCH64_COPY)
89 			continue;
90 
91 		dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
92 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
93 		name = dstobj->strtab + dstsym->st_name;
94 		size = dstsym->st_size;
95 
96 		symlook_init(&req, name);
97 		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
98 		req.flags = SYMLOOK_EARLY;
99 
100 		for (srcobj = globallist_next(dstobj); srcobj != NULL;
101 		     srcobj = globallist_next(srcobj)) {
102 			res = symlook_obj(&req, srcobj);
103 			if (res == 0) {
104 				srcsym = req.sym_out;
105 				defobj = req.defobj_out;
106 				break;
107 			}
108 		}
109 		if (srcobj == NULL) {
110 			_rtld_error("Undefined symbol \"%s\" referenced from "
111 			    "COPY relocation in %s", name, dstobj->path);
112 			return (-1);
113 		}
114 
115 		srcaddr = (const void *)(defobj->relocbase + srcsym->st_value);
116 		memcpy(dstaddr, srcaddr, size);
117 	}
118 
119 	return (0);
120 }
121 
122 struct tls_data {
123 	Elf_Addr	dtv_gen;
124 	int		tls_index;
125 	Elf_Addr	tls_offs;
126 };
127 
128 static Elf_Addr
129 reloc_tlsdesc_alloc(int tlsindex, Elf_Addr tlsoffs)
130 {
131 	struct tls_data *tlsdesc;
132 
133 	tlsdesc = xmalloc(sizeof(struct tls_data));
134 	tlsdesc->dtv_gen = tls_dtv_generation;
135 	tlsdesc->tls_index = tlsindex;
136 	tlsdesc->tls_offs = tlsoffs;
137 
138 	return ((Elf_Addr)tlsdesc);
139 }
140 
141 static void
142 reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where,
143     int flags, RtldLockState *lockstate)
144 {
145 	const Elf_Sym *def;
146 	const Obj_Entry *defobj;
147 	Elf_Addr offs;
148 
149 
150 	offs = 0;
151 	if (ELF_R_SYM(rela->r_info) != 0) {
152 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags,
153 			    NULL, lockstate);
154 		if (def == NULL)
155 			rtld_die();
156 		offs = def->st_value;
157 		obj = defobj;
158 		if (def->st_shndx == SHN_UNDEF) {
159 			/* Weak undefined thread variable */
160 			where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
161 			where[1] = rela->r_addend;
162 			return;
163 		}
164 	}
165 	offs += rela->r_addend;
166 
167 	if (obj->tlsoffset != 0) {
168 		/* Variable is in initialy allocated TLS segment */
169 		where[0] = (Elf_Addr)_rtld_tlsdesc_static;
170 		where[1] = obj->tlsoffset + offs;
171 	} else {
172 		/* TLS offest is unknown at load time, use dynamic resolving */
173 		where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
174 		where[1] = reloc_tlsdesc_alloc(obj->tlsindex, offs);
175 	}
176 }
177 
178 /*
179  * Process the PLT relocations.
180  */
181 int
182 reloc_plt(Obj_Entry *obj, int flags, RtldLockState *lockstate)
183 {
184 	const Elf_Rela *relalim;
185 	const Elf_Rela *rela;
186 
187 	relalim = (const Elf_Rela *)((const char *)obj->pltrela +
188 	    obj->pltrelasize);
189 	for (rela = obj->pltrela; rela < relalim; rela++) {
190 		Elf_Addr *where;
191 
192 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
193 
194 		switch(ELF_R_TYPE(rela->r_info)) {
195 		case R_AARCH64_JUMP_SLOT:
196 			*where += (Elf_Addr)obj->relocbase;
197 			break;
198 		case R_AARCH64_TLSDESC:
199 			reloc_tlsdesc(obj, rela, where, SYMLOOK_IN_PLT | flags,
200 			    lockstate);
201 			break;
202 		case R_AARCH64_IRELATIVE:
203 			obj->irelative = true;
204 			break;
205 		case R_AARCH64_NONE:
206 			break;
207 		default:
208 			_rtld_error("Unknown relocation type %u in PLT",
209 			    (unsigned int)ELF_R_TYPE(rela->r_info));
210 			return (-1);
211 		}
212 	}
213 
214 	return (0);
215 }
216 
217 /*
218  * LD_BIND_NOW was set - force relocation for all jump slots
219  */
220 int
221 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
222 {
223 	const Obj_Entry *defobj;
224 	const Elf_Rela *relalim;
225 	const Elf_Rela *rela;
226 	const Elf_Sym *def;
227 
228 	if (obj->jmpslots_done)
229 		return (0);
230 
231 	relalim = (const Elf_Rela *)((const char *)obj->pltrela +
232 	    obj->pltrelasize);
233 	for (rela = obj->pltrela; rela < relalim; rela++) {
234 		Elf_Addr *where, target;
235 
236 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
237 		switch(ELF_R_TYPE(rela->r_info)) {
238 		case R_AARCH64_JUMP_SLOT:
239 			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
240 			    &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
241 			if (def == NULL)
242 				return (-1);
243 			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
244 				obj->gnu_ifunc = true;
245 				continue;
246 			}
247 			target = (Elf_Addr)(defobj->relocbase + def->st_value);
248 			reloc_jmpslot(where, target, defobj, obj,
249 			    (const Elf_Rel *)rela);
250 			break;
251 		}
252 	}
253 	obj->jmpslots_done = true;
254 
255 	return (0);
256 }
257 
258 static void
259 reloc_iresolve_one(Obj_Entry *obj, const Elf_Rela *rela,
260     RtldLockState *lockstate)
261 {
262 	Elf_Addr *where, target, *ptr;
263 
264 	ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
265 	where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
266 	lock_release(rtld_bind_lock, lockstate);
267 	target = call_ifunc_resolver(ptr);
268 	wlock_acquire(rtld_bind_lock, lockstate);
269 	*where = target;
270 }
271 
272 int
273 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
274 {
275 	const Elf_Rela *relalim;
276 	const Elf_Rela *rela;
277 
278 	if (!obj->irelative)
279 		return (0);
280 	obj->irelative = false;
281 	relalim = (const Elf_Rela *)((const char *)obj->pltrela +
282 	    obj->pltrelasize);
283 	for (rela = obj->pltrela;  rela < relalim;  rela++) {
284 		if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE)
285 			reloc_iresolve_one(obj, rela, lockstate);
286 	}
287 	return (0);
288 }
289 
290 int
291 reloc_iresolve_nonplt(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
292 {
293 	const Elf_Rela *relalim;
294 	const Elf_Rela *rela;
295 
296 	if (!obj->irelative_nonplt)
297 		return (0);
298 	obj->irelative_nonplt = false;
299 	relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
300 	for (rela = obj->rela;  rela < relalim;  rela++) {
301 		if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE)
302 			reloc_iresolve_one(obj, rela, lockstate);
303 	}
304 	return (0);
305 }
306 
307 int
308 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
309    struct Struct_RtldLockState *lockstate)
310 {
311 	const Elf_Rela *relalim;
312 	const Elf_Rela *rela;
313 	Elf_Addr *where, target;
314 	const Elf_Sym *def;
315 	const Obj_Entry *defobj;
316 
317 	if (!obj->gnu_ifunc)
318 		return (0);
319 	relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
320 	for (rela = obj->pltrela;  rela < relalim;  rela++) {
321 		if (ELF_R_TYPE(rela->r_info) == R_AARCH64_JUMP_SLOT) {
322 			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
323 			def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
324 			    SYMLOOK_IN_PLT | flags, NULL, lockstate);
325 			if (def == NULL)
326 				return (-1);
327 			if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
328 				continue;
329 			lock_release(rtld_bind_lock, lockstate);
330 			target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
331 			wlock_acquire(rtld_bind_lock, lockstate);
332 			reloc_jmpslot(where, target, defobj, obj,
333 			    (const Elf_Rel *)rela);
334 		}
335 	}
336 	obj->gnu_ifunc = false;
337 	return (0);
338 }
339 
340 Elf_Addr
341 reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
342     const Obj_Entry *defobj __unused, const Obj_Entry *obj __unused,
343     const Elf_Rel *rel)
344 {
345 
346 	assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT ||
347 	    ELF_R_TYPE(rel->r_info) == R_AARCH64_IRELATIVE);
348 
349 	if (*where != target && !ld_bind_not)
350 		*where = target;
351 	return (target);
352 }
353 
354 void
355 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
356 {
357 
358 }
359 
360 /*
361  * Process non-PLT relocations
362  */
363 int
364 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
365     RtldLockState *lockstate)
366 {
367 	const Obj_Entry *defobj;
368 	const Elf_Rela *relalim;
369 	const Elf_Rela *rela;
370 	const Elf_Sym *def;
371 	SymCache *cache;
372 	Elf_Addr *where, symval;
373 
374 	/*
375 	 * The dynamic loader may be called from a thread, we have
376 	 * limited amounts of stack available so we cannot use alloca().
377 	 */
378 	if (obj == obj_rtld)
379 		cache = NULL;
380 	else
381 		cache = calloc(obj->dynsymcount, sizeof(SymCache));
382 		/* No need to check for NULL here */
383 
384 	relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
385 	for (rela = obj->rela; rela < relalim; rela++) {
386 		/*
387 		 * First, resolve symbol for relocations which
388 		 * reference symbols.
389 		 */
390 		switch (ELF_R_TYPE(rela->r_info)) {
391 		case R_AARCH64_ABS64:
392 		case R_AARCH64_GLOB_DAT:
393 		case R_AARCH64_TLS_TPREL64:
394 		case R_AARCH64_TLS_DTPREL64:
395 		case R_AARCH64_TLS_DTPMOD64:
396 			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
397 			    &defobj, flags, cache, lockstate);
398 			if (def == NULL)
399 				return (-1);
400 			/*
401 			 * If symbol is IFUNC, only perform relocation
402 			 * when caller allowed it by passing
403 			 * SYMLOOK_IFUNC flag.  Skip the relocations
404 			 * otherwise.
405 			 *
406 			 * Also error out in case IFUNC relocations
407 			 * are specified for TLS, which cannot be
408 			 * usefully interpreted.
409 			 */
410 			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
411 				switch (ELF_R_TYPE(rela->r_info)) {
412 				case R_AARCH64_ABS64:
413 				case R_AARCH64_GLOB_DAT:
414 					if ((flags & SYMLOOK_IFUNC) == 0) {
415 						obj->non_plt_gnu_ifunc = true;
416 						continue;
417 					}
418 					symval = (Elf_Addr)rtld_resolve_ifunc(
419 					    defobj, def);
420 					break;
421 				default:
422 					_rtld_error("%s: IFUNC for TLS reloc",
423 					    obj->path);
424 					return (-1);
425 				}
426 			} else {
427 				if ((flags & SYMLOOK_IFUNC) != 0)
428 					continue;
429 				symval = (Elf_Addr)defobj->relocbase +
430 				    def->st_value;
431 			}
432 			break;
433 		default:
434 			if ((flags & SYMLOOK_IFUNC) != 0)
435 				continue;
436 		}
437 
438 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
439 
440 		switch (ELF_R_TYPE(rela->r_info)) {
441 		case R_AARCH64_ABS64:
442 		case R_AARCH64_GLOB_DAT:
443 			*where = symval + rela->r_addend;
444 			break;
445 		case R_AARCH64_COPY:
446 			/*
447 			 * These are deferred until all other relocations have
448 			 * been done. All we do here is make sure that the
449 			 * COPY relocation is not in a shared library. They
450 			 * are allowed only in executable files.
451 			 */
452 			if (!obj->mainprog) {
453 				_rtld_error("%s: Unexpected R_AARCH64_COPY "
454 				    "relocation in shared library", obj->path);
455 				return (-1);
456 			}
457 			break;
458 		case R_AARCH64_TLSDESC:
459 			reloc_tlsdesc(obj, rela, where, flags, lockstate);
460 			break;
461 		case R_AARCH64_TLS_TPREL64:
462 			/*
463 			 * We lazily allocate offsets for static TLS as we
464 			 * see the first relocation that references the
465 			 * TLS block. This allows us to support (small
466 			 * amounts of) static TLS in dynamically loaded
467 			 * modules. If we run out of space, we generate an
468 			 * error.
469 			 */
470 			if (!defobj->tls_static) {
471 				if (!allocate_tls_offset(
472 				    __DECONST(Obj_Entry *, defobj))) {
473 					_rtld_error(
474 					    "%s: No space available for static "
475 					    "Thread Local Storage", obj->path);
476 					return (-1);
477 				}
478 			}
479 			*where = def->st_value + rela->r_addend +
480 			    defobj->tlsoffset;
481 			break;
482 
483 		/*
484 		 * !!! BEWARE !!!
485 		 * ARM ELF ABI defines TLS_DTPMOD64 as 1029, and TLS_DTPREL64
486 		 * as 1028. But actual bfd linker and the glibc RTLD linker
487 		 * treats TLS_DTPMOD64 as 1028 and TLS_DTPREL64 1029.
488 		 */
489 		case R_AARCH64_TLS_DTPREL64: /* efectively is TLS_DTPMOD64 */
490 			*where += (Elf_Addr)defobj->tlsindex;
491 			break;
492 		case R_AARCH64_TLS_DTPMOD64: /* efectively is TLS_DTPREL64 */
493 			*where += (Elf_Addr)(def->st_value + rela->r_addend);
494 			break;
495 		case R_AARCH64_RELATIVE:
496 			*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
497 			break;
498 		case R_AARCH64_NONE:
499 			break;
500 		case R_AARCH64_IRELATIVE:
501 			obj->irelative_nonplt = true;
502 			break;
503 		default:
504 			rtld_printf("%s: Unhandled relocation %lu\n",
505 			    obj->path, ELF_R_TYPE(rela->r_info));
506 			return (-1);
507 		}
508 	}
509 
510 	return (0);
511 }
512 
513 void
514 allocate_initial_tls(Obj_Entry *objs)
515 {
516 
517 	/*
518 	* Fix the size of the static TLS block by using the maximum
519 	* offset allocated so far and adding a bit for dynamic modules to
520 	* use.
521 	*/
522 	tls_static_space = tls_last_offset + tls_last_size +
523 	    ld_static_tls_extra;
524 
525 	_tcb_set(allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN));
526 }
527 
528 void *
529 __tls_get_addr(tls_index* ti)
530 {
531 	uintptr_t **dtvp;
532 
533 	dtvp = &_tcb_get()->tcb_dtv;
534 	return (tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset));
535 }
536