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