2 * Copyright (c) 2014-2015 The FreeBSD Foundation
5 * Portions of this software were developed by Andrew Turner
6 * under sponsorship from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
39 #include "rtld_printf.h"
42 * It is possible for the compiler to emit relocations for unaligned data.
43 * We handle this situation with these inlines.
45 #define RELOC_ALIGNED_P(x) \
46 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
49 * This is not the correct prototype, but we only need it for
50 * a function pointer to a simple asm function.
52 void *_rtld_tlsdesc_static(void *);
53 void *_rtld_tlsdesc_undef(void *);
54 void *_rtld_tlsdesc_dynamic(void *);
59 init_pltgot(Obj_Entry *obj)
62 if (obj->pltgot != NULL) {
63 obj->pltgot[1] = (Elf_Addr) obj;
64 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
69 do_copy_relocations(Obj_Entry *dstobj)
71 const Obj_Entry *srcobj, *defobj;
72 const Elf_Rela *relalim;
74 const Elf_Sym *srcsym;
75 const Elf_Sym *dstsym;
84 * COPY relocs are invalid outside of the main program
86 assert(dstobj->mainprog);
88 relalim = (const Elf_Rela *)((const char *)dstobj->rela +
90 for (rela = dstobj->rela; rela < relalim; rela++) {
91 if (ELF_R_TYPE(rela->r_info) != R_AARCH64_COPY)
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;
99 symlook_init(&req, name);
100 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
101 req.flags = SYMLOOK_EARLY;
103 for (srcobj = globallist_next(dstobj); srcobj != NULL;
104 srcobj = globallist_next(srcobj)) {
105 res = symlook_obj(&req, srcobj);
107 srcsym = req.sym_out;
108 defobj = req.defobj_out;
112 if (srcobj == NULL) {
113 _rtld_error("Undefined symbol \"%s\" referenced from "
114 "COPY relocation in %s", name, dstobj->path);
118 srcaddr = (const void *)(defobj->relocbase + srcsym->st_value);
119 memcpy(dstaddr, srcaddr, size);
131 int64_t rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags);
134 reloc_tlsdesc_alloc(int tlsindex, Elf_Addr tlsoffs)
136 struct tls_data *tlsdesc;
138 tlsdesc = xmalloc(sizeof(struct tls_data));
139 tlsdesc->dtv_gen = tls_dtv_generation;
140 tlsdesc->tls_index = tlsindex;
141 tlsdesc->tls_offs = tlsoffs;
143 return ((Elf_Addr)tlsdesc);
147 reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where,
148 int flags, RtldLockState *lockstate)
151 const Obj_Entry *defobj;
156 if (ELF_R_SYM(rela->r_info) != 0) {
157 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags,
161 offs = def->st_value;
163 if (def->st_shndx == SHN_UNDEF) {
164 /* Weak undefined thread variable */
165 where[0] = (Elf_Addr)_rtld_tlsdesc_undef;
166 where[1] = rela->r_addend;
170 offs += rela->r_addend;
172 if (obj->tlsoffset != 0) {
173 /* Variable is in initialy allocated TLS segment */
174 where[0] = (Elf_Addr)_rtld_tlsdesc_static;
175 where[1] = obj->tlsoffset + offs;
177 /* TLS offest is unknown at load time, use dynamic resolving */
178 where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
179 where[1] = reloc_tlsdesc_alloc(obj->tlsindex, offs);
184 * Process the PLT relocations.
187 reloc_plt(Obj_Entry *obj, int flags, RtldLockState *lockstate)
189 const Elf_Rela *relalim;
190 const Elf_Rela *rela;
192 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
193 for (rela = obj->pltrela; rela < relalim; rela++) {
196 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
198 switch(ELF_R_TYPE(rela->r_info)) {
199 case R_AARCH64_JUMP_SLOT:
200 *where += (Elf_Addr)obj->relocbase;
202 case R_AARCH64_TLSDESC:
203 reloc_tlsdesc(obj, rela, where, SYMLOOK_IN_PLT | flags,
206 case R_AARCH64_IRELATIVE:
207 obj->irelative = true;
212 _rtld_error("Unknown relocation type %u in PLT",
213 (unsigned int)ELF_R_TYPE(rela->r_info));
222 * LD_BIND_NOW was set - force relocation for all jump slots
225 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
227 const Obj_Entry *defobj;
228 const Elf_Rela *relalim;
229 const Elf_Rela *rela;
232 if (obj->jmpslots_done)
235 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
236 for (rela = obj->pltrela; rela < relalim; rela++) {
237 Elf_Addr *where, target;
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);
246 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
247 obj->gnu_ifunc = true;
250 target = (Elf_Addr)(defobj->relocbase + def->st_value);
251 reloc_jmpslot(where, target, defobj, obj,
252 (const Elf_Rel *)rela);
256 obj->jmpslots_done = true;
262 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
264 const Elf_Rela *relalim;
265 const Elf_Rela *rela;
266 Elf_Addr *where, target, *ptr;
270 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
271 for (rela = obj->pltrela; rela < relalim; rela++) {
272 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE) {
273 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
274 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
275 lock_release(rtld_bind_lock, lockstate);
276 target = call_ifunc_resolver(ptr);
277 wlock_acquire(rtld_bind_lock, lockstate);
281 obj->irelative = false;
286 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
287 struct Struct_RtldLockState *lockstate)
289 const Elf_Rela *relalim;
290 const Elf_Rela *rela;
291 Elf_Addr *where, target;
293 const Obj_Entry *defobj;
297 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
298 for (rela = obj->pltrela; rela < relalim; rela++) {
299 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_JUMP_SLOT) {
300 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
301 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
302 SYMLOOK_IN_PLT | flags, NULL, lockstate);
305 if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
307 lock_release(rtld_bind_lock, lockstate);
308 target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
309 wlock_acquire(rtld_bind_lock, lockstate);
310 reloc_jmpslot(where, target, defobj, obj,
311 (const Elf_Rel *)rela);
314 obj->gnu_ifunc = false;
319 reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
320 const Obj_Entry *defobj __unused, const Obj_Entry *obj __unused,
324 assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT ||
325 ELF_R_TYPE(rel->r_info) == R_AARCH64_IRELATIVE);
327 if (*where != target && !ld_bind_not)
333 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
345 * Process non-PLT relocations
348 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
349 RtldLockState *lockstate)
351 const Obj_Entry *defobj;
352 const Elf_Rela *relalim;
353 const Elf_Rela *rela;
356 Elf_Addr *where, symval;
359 * The dynamic loader may be called from a thread, we have
360 * limited amounts of stack available so we cannot use alloca().
365 cache = calloc(obj->dynsymcount, sizeof(SymCache));
366 /* No need to check for NULL here */
368 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
369 for (rela = obj->rela; rela < relalim; rela++) {
371 * First, resolve symbol for relocations which
374 switch (ELF_R_TYPE(rela->r_info)) {
375 case R_AARCH64_ABS64:
376 case R_AARCH64_GLOB_DAT:
377 case R_AARCH64_TLS_TPREL64:
378 case R_AARCH64_TLS_DTPREL64:
379 case R_AARCH64_TLS_DTPMOD64:
380 def = find_symdef(ELF_R_SYM(rela->r_info), obj,
381 &defobj, flags, cache, lockstate);
385 * If symbol is IFUNC, only perform relocation
386 * when caller allowed it by passing
387 * SYMLOOK_IFUNC flag. Skip the relocations
390 * Also error out in case IFUNC relocations
391 * are specified for TLS, which cannot be
392 * usefully interpreted.
394 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
395 switch (ELF_R_TYPE(rela->r_info)) {
396 case R_AARCH64_ABS64:
397 case R_AARCH64_GLOB_DAT:
398 if ((flags & SYMLOOK_IFUNC) == 0) {
399 obj->non_plt_gnu_ifunc = true;
402 symval = (Elf_Addr)rtld_resolve_ifunc(
406 _rtld_error("%s: IFUNC for TLS reloc",
411 if ((flags & SYMLOOK_IFUNC) != 0)
413 symval = (Elf_Addr)defobj->relocbase +
418 if ((flags & SYMLOOK_IFUNC) != 0)
422 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
424 switch (ELF_R_TYPE(rela->r_info)) {
425 case R_AARCH64_ABS64:
426 case R_AARCH64_GLOB_DAT:
427 *where = symval + rela->r_addend;
431 * These are deferred until all other relocations have
432 * been done. All we do here is make sure that the
433 * COPY relocation is not in a shared library. They
434 * are allowed only in executable files.
436 if (!obj->mainprog) {
437 _rtld_error("%s: Unexpected R_AARCH64_COPY "
438 "relocation in shared library", obj->path);
442 case R_AARCH64_TLSDESC:
443 reloc_tlsdesc(obj, rela, where, flags, lockstate);
445 case R_AARCH64_TLS_TPREL64:
447 * We lazily allocate offsets for static TLS as we
448 * see the first relocation that references the
449 * TLS block. This allows us to support (small
450 * amounts of) static TLS in dynamically loaded
451 * modules. If we run out of space, we generate an
454 if (!defobj->tls_done) {
455 if (!allocate_tls_offset(
456 __DECONST(Obj_Entry *, defobj))) {
458 "%s: No space available for static "
459 "Thread Local Storage", obj->path);
463 /* Test weak undefined thread variable */
464 if (def->st_shndx != SHN_UNDEF) {
465 *where = def->st_value + rela->r_addend +
469 * XXX We should relocate undefined thread
470 * weak variable address to NULL, but how?
471 * Can we return error in this situation?
473 rtld_printf("%s: Unable to relocate undefined "
474 "weak TLS variable\n", obj->path);
478 *where = def->st_value + rela->r_addend +
486 * ARM ELF ABI defines TLS_DTPMOD64 as 1029, and TLS_DTPREL64
487 * as 1028. But actual bfd linker and the glibc RTLD linker
488 * treats TLS_DTPMOD64 as 1028 and TLS_DTPREL64 1029.
490 case R_AARCH64_TLS_DTPREL64: /* efectively is TLS_DTPMOD64 */
491 *where += (Elf_Addr)defobj->tlsindex;
493 case R_AARCH64_TLS_DTPMOD64: /* efectively is TLS_DTPREL64 */
494 *where += (Elf_Addr)(def->st_value + rela->r_addend);
496 case R_AARCH64_RELATIVE:
497 *where = (Elf_Addr)(obj->relocbase + rela->r_addend);
502 rtld_printf("%s: Unhandled relocation %lu\n",
503 obj->path, ELF_R_TYPE(rela->r_info));
512 allocate_initial_tls(Obj_Entry *objs)
517 * Fix the size of the static TLS block by using the maximum
518 * offset allocated so far and adding a bit for dynamic modules to
521 tls_static_space = tls_last_offset + tls_last_size +
522 RTLD_STATIC_TLS_EXTRA;
524 tp = (Elf_Addr **) allocate_tls(objs, NULL, TLS_TCB_SIZE, 16);
526 asm volatile("msr tpidr_el0, %0" : : "r"(tp));
530 __tls_get_addr(tls_index* ti)
535 __asm __volatile("mrs %0, tpidr_el0" : "=r" (_tp));
536 p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset);