1047c6e3aSAndrew Turner /*- 2f5f299c3SEd Maste * Copyright (c) 2014-2015 The FreeBSD Foundation 3047c6e3aSAndrew Turner * All rights reserved. 4047c6e3aSAndrew Turner * 5047c6e3aSAndrew Turner * Portions of this software were developed by Andrew Turner 6047c6e3aSAndrew Turner * under sponsorship from the FreeBSD Foundation. 7047c6e3aSAndrew Turner * 8047c6e3aSAndrew Turner * Redistribution and use in source and binary forms, with or without 9047c6e3aSAndrew Turner * modification, are permitted provided that the following conditions 10047c6e3aSAndrew Turner * are met: 11047c6e3aSAndrew Turner * 1. Redistributions of source code must retain the above copyright 12047c6e3aSAndrew Turner * notice, this list of conditions and the following disclaimer. 13047c6e3aSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 14047c6e3aSAndrew Turner * notice, this list of conditions and the following disclaimer in the 15047c6e3aSAndrew Turner * documentation and/or other materials provided with the distribution. 16047c6e3aSAndrew Turner * 17047c6e3aSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18047c6e3aSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19047c6e3aSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20047c6e3aSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21047c6e3aSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22047c6e3aSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23047c6e3aSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24047c6e3aSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25047c6e3aSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26047c6e3aSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27047c6e3aSAndrew Turner * SUCH DAMAGE. 28047c6e3aSAndrew Turner */ 29047c6e3aSAndrew Turner 30047c6e3aSAndrew Turner #include <sys/cdefs.h> 31047c6e3aSAndrew Turner __FBSDID("$FreeBSD$"); 32047c6e3aSAndrew Turner 33047c6e3aSAndrew Turner #include <sys/types.h> 34047c6e3aSAndrew Turner 35047c6e3aSAndrew Turner #include <stdlib.h> 36047c6e3aSAndrew Turner 37047c6e3aSAndrew Turner #include "debug.h" 38047c6e3aSAndrew Turner #include "rtld.h" 39047c6e3aSAndrew Turner #include "rtld_printf.h" 40047c6e3aSAndrew Turner 41047c6e3aSAndrew Turner /* 42047c6e3aSAndrew Turner * It is possible for the compiler to emit relocations for unaligned data. 43047c6e3aSAndrew Turner * We handle this situation with these inlines. 44047c6e3aSAndrew Turner */ 45047c6e3aSAndrew Turner #define RELOC_ALIGNED_P(x) \ 46047c6e3aSAndrew Turner (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) 47047c6e3aSAndrew Turner 48047c6e3aSAndrew Turner /* 49047c6e3aSAndrew Turner * This is not the correct prototype, but we only need it for 50047c6e3aSAndrew Turner * a function pointer to a simple asm function. 51047c6e3aSAndrew Turner */ 52*4849c3a5SMichal Meloun void *_rtld_tlsdesc_static(void *); 53*4849c3a5SMichal Meloun void *_rtld_tlsdesc_undef(void *); 54a97120d6SAndrew Turner void *_rtld_tlsdesc_dynamic(void *); 55a97120d6SAndrew Turner 56047c6e3aSAndrew Turner void _exit(int); 57047c6e3aSAndrew Turner 58047c6e3aSAndrew Turner void 59047c6e3aSAndrew Turner init_pltgot(Obj_Entry *obj) 60047c6e3aSAndrew Turner { 61047c6e3aSAndrew Turner 62047c6e3aSAndrew Turner if (obj->pltgot != NULL) { 63047c6e3aSAndrew Turner obj->pltgot[1] = (Elf_Addr) obj; 64047c6e3aSAndrew Turner obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 65047c6e3aSAndrew Turner } 66047c6e3aSAndrew Turner } 67047c6e3aSAndrew Turner 68047c6e3aSAndrew Turner int 69047c6e3aSAndrew Turner do_copy_relocations(Obj_Entry *dstobj) 70047c6e3aSAndrew Turner { 71047c6e3aSAndrew Turner const Obj_Entry *srcobj, *defobj; 72047c6e3aSAndrew Turner const Elf_Rela *relalim; 73047c6e3aSAndrew Turner const Elf_Rela *rela; 74047c6e3aSAndrew Turner const Elf_Sym *srcsym; 75047c6e3aSAndrew Turner const Elf_Sym *dstsym; 76047c6e3aSAndrew Turner const void *srcaddr; 77047c6e3aSAndrew Turner const char *name; 78047c6e3aSAndrew Turner void *dstaddr; 79047c6e3aSAndrew Turner SymLook req; 80047c6e3aSAndrew Turner size_t size; 81047c6e3aSAndrew Turner int res; 82047c6e3aSAndrew Turner 83047c6e3aSAndrew Turner /* 84047c6e3aSAndrew Turner * COPY relocs are invalid outside of the main program 85047c6e3aSAndrew Turner */ 86047c6e3aSAndrew Turner assert(dstobj->mainprog); 87047c6e3aSAndrew Turner 88903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)dstobj->rela + 89047c6e3aSAndrew Turner dstobj->relasize); 90047c6e3aSAndrew Turner for (rela = dstobj->rela; rela < relalim; rela++) { 91047c6e3aSAndrew Turner if (ELF_R_TYPE(rela->r_info) != R_AARCH64_COPY) 92047c6e3aSAndrew Turner continue; 93047c6e3aSAndrew Turner 94047c6e3aSAndrew Turner dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 95047c6e3aSAndrew Turner dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 96047c6e3aSAndrew Turner name = dstobj->strtab + dstsym->st_name; 97047c6e3aSAndrew Turner size = dstsym->st_size; 98047c6e3aSAndrew Turner 99047c6e3aSAndrew Turner symlook_init(&req, name); 100047c6e3aSAndrew Turner req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 101047c6e3aSAndrew Turner req.flags = SYMLOOK_EARLY; 102047c6e3aSAndrew Turner 1039fee0541SKonstantin Belousov for (srcobj = globallist_next(dstobj); srcobj != NULL; 1049fee0541SKonstantin Belousov srcobj = globallist_next(srcobj)) { 105047c6e3aSAndrew Turner res = symlook_obj(&req, srcobj); 106047c6e3aSAndrew Turner if (res == 0) { 107047c6e3aSAndrew Turner srcsym = req.sym_out; 108047c6e3aSAndrew Turner defobj = req.defobj_out; 109047c6e3aSAndrew Turner break; 110047c6e3aSAndrew Turner } 111047c6e3aSAndrew Turner } 112047c6e3aSAndrew Turner if (srcobj == NULL) { 113e8c479fdSMichal Meloun _rtld_error("Undefined symbol \"%s\" referenced from " 114e8c479fdSMichal Meloun "COPY relocation in %s", name, dstobj->path); 115047c6e3aSAndrew Turner return (-1); 116047c6e3aSAndrew Turner } 117047c6e3aSAndrew Turner 118047c6e3aSAndrew Turner srcaddr = (const void *)(defobj->relocbase + srcsym->st_value); 119047c6e3aSAndrew Turner memcpy(dstaddr, srcaddr, size); 120047c6e3aSAndrew Turner } 121047c6e3aSAndrew Turner 122047c6e3aSAndrew Turner return (0); 123047c6e3aSAndrew Turner } 124047c6e3aSAndrew Turner 125a97120d6SAndrew Turner struct tls_data { 126*4849c3a5SMichal Meloun Elf_Addr dtv_gen; 127*4849c3a5SMichal Meloun int tls_index; 128*4849c3a5SMichal Meloun Elf_Addr tls_offs; 129a97120d6SAndrew Turner }; 130a97120d6SAndrew Turner 131*4849c3a5SMichal Meloun static Elf_Addr 132*4849c3a5SMichal Meloun reloc_tlsdesc_alloc(int tlsindex, Elf_Addr tlsoffs) 133a97120d6SAndrew Turner { 134a97120d6SAndrew Turner struct tls_data *tlsdesc; 135a97120d6SAndrew Turner 136a97120d6SAndrew Turner tlsdesc = xmalloc(sizeof(struct tls_data)); 137*4849c3a5SMichal Meloun tlsdesc->dtv_gen = tls_dtv_generation; 138*4849c3a5SMichal Meloun tlsdesc->tls_index = tlsindex; 139*4849c3a5SMichal Meloun tlsdesc->tls_offs = tlsoffs; 140a97120d6SAndrew Turner 141*4849c3a5SMichal Meloun return ((Elf_Addr)tlsdesc); 142a97120d6SAndrew Turner } 143a97120d6SAndrew Turner 14402dbdb16SAndrew Turner static void 145*4849c3a5SMichal Meloun reloc_tlsdesc(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where, 146*4849c3a5SMichal Meloun int flags, RtldLockState *lockstate) 14702dbdb16SAndrew Turner { 148*4849c3a5SMichal Meloun const Elf_Sym *def; 149*4849c3a5SMichal Meloun const Obj_Entry *defobj; 150*4849c3a5SMichal Meloun Elf_Addr offs; 151*4849c3a5SMichal Meloun 152*4849c3a5SMichal Meloun 153*4849c3a5SMichal Meloun offs = 0; 154*4849c3a5SMichal Meloun if (ELF_R_SYM(rela->r_info) != 0) { 155*4849c3a5SMichal Meloun def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags, 156*4849c3a5SMichal Meloun NULL, lockstate); 157*4849c3a5SMichal Meloun if (def == NULL) 158*4849c3a5SMichal Meloun rtld_die(); 159*4849c3a5SMichal Meloun offs = def->st_value; 160*4849c3a5SMichal Meloun obj = defobj; 161*4849c3a5SMichal Meloun if (def->st_shndx == SHN_UNDEF) { 162*4849c3a5SMichal Meloun /* Weak undefined thread variable */ 163*4849c3a5SMichal Meloun where[0] = (Elf_Addr)_rtld_tlsdesc_undef; 164*4849c3a5SMichal Meloun where[1] = rela->r_addend; 165*4849c3a5SMichal Meloun return; 166*4849c3a5SMichal Meloun } 167*4849c3a5SMichal Meloun } 168*4849c3a5SMichal Meloun offs += rela->r_addend; 169*4849c3a5SMichal Meloun 170*4849c3a5SMichal Meloun if (obj->tlsoffset != 0) { 171*4849c3a5SMichal Meloun /* Variable is in initialy allocated TLS segment */ 172*4849c3a5SMichal Meloun where[0] = (Elf_Addr)_rtld_tlsdesc_static; 173*4849c3a5SMichal Meloun where[1] = obj->tlsoffset + offs; 17402dbdb16SAndrew Turner } else { 175*4849c3a5SMichal Meloun /* TLS offest is unknown at load time, use dynamic resolving */ 17602dbdb16SAndrew Turner where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic; 177*4849c3a5SMichal Meloun where[1] = reloc_tlsdesc_alloc(obj->tlsindex, offs); 17802dbdb16SAndrew Turner } 17902dbdb16SAndrew Turner } 18002dbdb16SAndrew Turner 181047c6e3aSAndrew Turner /* 182047c6e3aSAndrew Turner * Process the PLT relocations. 183047c6e3aSAndrew Turner */ 184047c6e3aSAndrew Turner int 185*4849c3a5SMichal Meloun reloc_plt(Obj_Entry *obj, int flags, RtldLockState *lockstate) 186047c6e3aSAndrew Turner { 187047c6e3aSAndrew Turner const Elf_Rela *relalim; 188047c6e3aSAndrew Turner const Elf_Rela *rela; 189047c6e3aSAndrew Turner 190e8c479fdSMichal Meloun relalim = (const Elf_Rela *)((const char *)obj->pltrela + 191e8c479fdSMichal Meloun obj->pltrelasize); 192047c6e3aSAndrew Turner for (rela = obj->pltrela; rela < relalim; rela++) { 193047c6e3aSAndrew Turner Elf_Addr *where; 194047c6e3aSAndrew Turner 195047c6e3aSAndrew Turner where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 196047c6e3aSAndrew Turner 197047c6e3aSAndrew Turner switch(ELF_R_TYPE(rela->r_info)) { 198047c6e3aSAndrew Turner case R_AARCH64_JUMP_SLOT: 199047c6e3aSAndrew Turner *where += (Elf_Addr)obj->relocbase; 200047c6e3aSAndrew Turner break; 201047c6e3aSAndrew Turner case R_AARCH64_TLSDESC: 202*4849c3a5SMichal Meloun reloc_tlsdesc(obj, rela, where, SYMLOOK_IN_PLT | flags, 203*4849c3a5SMichal Meloun lockstate); 204047c6e3aSAndrew Turner break; 2056e4fdb5cSAndrew Turner case R_AARCH64_IRELATIVE: 2066e4fdb5cSAndrew Turner obj->irelative = true; 2076e4fdb5cSAndrew Turner break; 20863003c4bSMichal Meloun case R_AARCH64_NONE: 20963003c4bSMichal Meloun break; 210047c6e3aSAndrew Turner default: 211047c6e3aSAndrew Turner _rtld_error("Unknown relocation type %u in PLT", 212047c6e3aSAndrew Turner (unsigned int)ELF_R_TYPE(rela->r_info)); 213047c6e3aSAndrew Turner return (-1); 214047c6e3aSAndrew Turner } 215047c6e3aSAndrew Turner } 216047c6e3aSAndrew Turner 217047c6e3aSAndrew Turner return (0); 218047c6e3aSAndrew Turner } 219047c6e3aSAndrew Turner 220047c6e3aSAndrew Turner /* 221047c6e3aSAndrew Turner * LD_BIND_NOW was set - force relocation for all jump slots 222047c6e3aSAndrew Turner */ 223047c6e3aSAndrew Turner int 224047c6e3aSAndrew Turner reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 225047c6e3aSAndrew Turner { 226047c6e3aSAndrew Turner const Obj_Entry *defobj; 227047c6e3aSAndrew Turner const Elf_Rela *relalim; 228047c6e3aSAndrew Turner const Elf_Rela *rela; 229047c6e3aSAndrew Turner const Elf_Sym *def; 230419333b9SMichal Meloun 231419333b9SMichal Meloun if (obj->jmpslots_done) 232419333b9SMichal Meloun return (0); 233047c6e3aSAndrew Turner 234e8c479fdSMichal Meloun relalim = (const Elf_Rela *)((const char *)obj->pltrela + 235e8c479fdSMichal Meloun obj->pltrelasize); 236047c6e3aSAndrew Turner for (rela = obj->pltrela; rela < relalim; rela++) { 2376e4fdb5cSAndrew Turner Elf_Addr *where, target; 238047c6e3aSAndrew Turner 239a97120d6SAndrew Turner where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 240047c6e3aSAndrew Turner switch(ELF_R_TYPE(rela->r_info)) { 241047c6e3aSAndrew Turner case R_AARCH64_JUMP_SLOT: 242047c6e3aSAndrew Turner def = find_symdef(ELF_R_SYM(rela->r_info), obj, 243047c6e3aSAndrew Turner &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate); 2446e4fdb5cSAndrew Turner if (def == NULL) 245047c6e3aSAndrew Turner return (-1); 2466e4fdb5cSAndrew Turner if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 2476e4fdb5cSAndrew Turner obj->gnu_ifunc = true; 2486e4fdb5cSAndrew Turner continue; 249047c6e3aSAndrew Turner } 2506e4fdb5cSAndrew Turner target = (Elf_Addr)(defobj->relocbase + def->st_value); 2516e4fdb5cSAndrew Turner reloc_jmpslot(where, target, defobj, obj, 2526e4fdb5cSAndrew Turner (const Elf_Rel *)rela); 253047c6e3aSAndrew Turner break; 254047c6e3aSAndrew Turner } 255047c6e3aSAndrew Turner } 256419333b9SMichal Meloun obj->jmpslots_done = true; 257047c6e3aSAndrew Turner 258047c6e3aSAndrew Turner return (0); 259047c6e3aSAndrew Turner } 260047c6e3aSAndrew Turner 261047c6e3aSAndrew Turner int 262047c6e3aSAndrew Turner reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 263047c6e3aSAndrew Turner { 2646e4fdb5cSAndrew Turner const Elf_Rela *relalim; 2656e4fdb5cSAndrew Turner const Elf_Rela *rela; 2666e4fdb5cSAndrew Turner Elf_Addr *where, target, *ptr; 267047c6e3aSAndrew Turner 2686e4fdb5cSAndrew Turner if (!obj->irelative) 2696e4fdb5cSAndrew Turner return (0); 270903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 2716e4fdb5cSAndrew Turner for (rela = obj->pltrela; rela < relalim; rela++) { 2726e4fdb5cSAndrew Turner if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE) { 2736e4fdb5cSAndrew Turner ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 2746e4fdb5cSAndrew Turner where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 2756e4fdb5cSAndrew Turner lock_release(rtld_bind_lock, lockstate); 2766e4fdb5cSAndrew Turner target = call_ifunc_resolver(ptr); 2776e4fdb5cSAndrew Turner wlock_acquire(rtld_bind_lock, lockstate); 2786e4fdb5cSAndrew Turner *where = target; 2796e4fdb5cSAndrew Turner } 2806e4fdb5cSAndrew Turner } 2816e4fdb5cSAndrew Turner obj->irelative = false; 282047c6e3aSAndrew Turner return (0); 283047c6e3aSAndrew Turner } 284047c6e3aSAndrew Turner 285047c6e3aSAndrew Turner int 286047c6e3aSAndrew Turner reloc_gnu_ifunc(Obj_Entry *obj, int flags, 287047c6e3aSAndrew Turner struct Struct_RtldLockState *lockstate) 288047c6e3aSAndrew Turner { 2896e4fdb5cSAndrew Turner const Elf_Rela *relalim; 2906e4fdb5cSAndrew Turner const Elf_Rela *rela; 2916e4fdb5cSAndrew Turner Elf_Addr *where, target; 2926e4fdb5cSAndrew Turner const Elf_Sym *def; 2936e4fdb5cSAndrew Turner const Obj_Entry *defobj; 294047c6e3aSAndrew Turner 2956e4fdb5cSAndrew Turner if (!obj->gnu_ifunc) 2966e4fdb5cSAndrew Turner return (0); 297903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 2986e4fdb5cSAndrew Turner for (rela = obj->pltrela; rela < relalim; rela++) { 2996e4fdb5cSAndrew Turner if (ELF_R_TYPE(rela->r_info) == R_AARCH64_JUMP_SLOT) { 3006e4fdb5cSAndrew Turner where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 3016e4fdb5cSAndrew Turner def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 3026e4fdb5cSAndrew Turner SYMLOOK_IN_PLT | flags, NULL, lockstate); 3036e4fdb5cSAndrew Turner if (def == NULL) 3046e4fdb5cSAndrew Turner return (-1); 3056e4fdb5cSAndrew Turner if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 3066e4fdb5cSAndrew Turner continue; 3076e4fdb5cSAndrew Turner lock_release(rtld_bind_lock, lockstate); 3086e4fdb5cSAndrew Turner target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 3096e4fdb5cSAndrew Turner wlock_acquire(rtld_bind_lock, lockstate); 3106e4fdb5cSAndrew Turner reloc_jmpslot(where, target, defobj, obj, 3116e4fdb5cSAndrew Turner (const Elf_Rel *)rela); 3126e4fdb5cSAndrew Turner } 3136e4fdb5cSAndrew Turner } 3146e4fdb5cSAndrew Turner obj->gnu_ifunc = false; 315047c6e3aSAndrew Turner return (0); 316047c6e3aSAndrew Turner } 317047c6e3aSAndrew Turner 318047c6e3aSAndrew Turner Elf_Addr 319903e0ffdSAlex Richardson reloc_jmpslot(Elf_Addr *where, Elf_Addr target, 320903e0ffdSAlex Richardson const Obj_Entry *defobj __unused, const Obj_Entry *obj __unused, 321903e0ffdSAlex Richardson const Elf_Rel *rel) 322047c6e3aSAndrew Turner { 323047c6e3aSAndrew Turner 3246e4fdb5cSAndrew Turner assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT || 3256e4fdb5cSAndrew Turner ELF_R_TYPE(rel->r_info) == R_AARCH64_IRELATIVE); 326047c6e3aSAndrew Turner 327e35ddbe4SKonstantin Belousov if (*where != target && !ld_bind_not) 328047c6e3aSAndrew Turner *where = target; 329e35ddbe4SKonstantin Belousov return (target); 330047c6e3aSAndrew Turner } 331047c6e3aSAndrew Turner 3324352999eSKonstantin Belousov void 333d27078f9SKonstantin Belousov ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 3344352999eSKonstantin Belousov { 33541fc6f68SMarius Strobl 33641fc6f68SMarius Strobl } 33741fc6f68SMarius Strobl 33841fc6f68SMarius Strobl void 33941fc6f68SMarius Strobl pre_init(void) 34041fc6f68SMarius Strobl { 34141fc6f68SMarius Strobl 3424352999eSKonstantin Belousov } 3434352999eSKonstantin Belousov 344047c6e3aSAndrew Turner /* 345047c6e3aSAndrew Turner * Process non-PLT relocations 346047c6e3aSAndrew Turner */ 347047c6e3aSAndrew Turner int 348047c6e3aSAndrew Turner reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 349047c6e3aSAndrew Turner RtldLockState *lockstate) 350047c6e3aSAndrew Turner { 351047c6e3aSAndrew Turner const Obj_Entry *defobj; 352047c6e3aSAndrew Turner const Elf_Rela *relalim; 353047c6e3aSAndrew Turner const Elf_Rela *rela; 354047c6e3aSAndrew Turner const Elf_Sym *def; 355047c6e3aSAndrew Turner SymCache *cache; 3566e4fdb5cSAndrew Turner Elf_Addr *where, symval; 357047c6e3aSAndrew Turner 358047c6e3aSAndrew Turner /* 359047c6e3aSAndrew Turner * The dynamic loader may be called from a thread, we have 360047c6e3aSAndrew Turner * limited amounts of stack available so we cannot use alloca(). 361047c6e3aSAndrew Turner */ 362047c6e3aSAndrew Turner if (obj == obj_rtld) 363047c6e3aSAndrew Turner cache = NULL; 364047c6e3aSAndrew Turner else 365047c6e3aSAndrew Turner cache = calloc(obj->dynsymcount, sizeof(SymCache)); 366047c6e3aSAndrew Turner /* No need to check for NULL here */ 367047c6e3aSAndrew Turner 368903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 369047c6e3aSAndrew Turner for (rela = obj->rela; rela < relalim; rela++) { 3706e4fdb5cSAndrew Turner /* 3716e4fdb5cSAndrew Turner * First, resolve symbol for relocations which 3726e4fdb5cSAndrew Turner * reference symbols. 3736e4fdb5cSAndrew Turner */ 3746e4fdb5cSAndrew Turner switch (ELF_R_TYPE(rela->r_info)) { 3756e4fdb5cSAndrew Turner case R_AARCH64_ABS64: 3766e4fdb5cSAndrew Turner case R_AARCH64_GLOB_DAT: 3776e4fdb5cSAndrew Turner case R_AARCH64_TLS_TPREL64: 37863003c4bSMichal Meloun case R_AARCH64_TLS_DTPREL64: 37963003c4bSMichal Meloun case R_AARCH64_TLS_DTPMOD64: 3806e4fdb5cSAndrew Turner def = find_symdef(ELF_R_SYM(rela->r_info), obj, 3816e4fdb5cSAndrew Turner &defobj, flags, cache, lockstate); 3826e4fdb5cSAndrew Turner if (def == NULL) 3836e4fdb5cSAndrew Turner return (-1); 3846e4fdb5cSAndrew Turner /* 3856e4fdb5cSAndrew Turner * If symbol is IFUNC, only perform relocation 3866e4fdb5cSAndrew Turner * when caller allowed it by passing 3876e4fdb5cSAndrew Turner * SYMLOOK_IFUNC flag. Skip the relocations 3886e4fdb5cSAndrew Turner * otherwise. 3896e4fdb5cSAndrew Turner * 3906e4fdb5cSAndrew Turner * Also error out in case IFUNC relocations 3916e4fdb5cSAndrew Turner * are specified for TLS, which cannot be 3926e4fdb5cSAndrew Turner * usefully interpreted. 3936e4fdb5cSAndrew Turner */ 3946e4fdb5cSAndrew Turner if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 3956e4fdb5cSAndrew Turner switch (ELF_R_TYPE(rela->r_info)) { 3966e4fdb5cSAndrew Turner case R_AARCH64_ABS64: 3976e4fdb5cSAndrew Turner case R_AARCH64_GLOB_DAT: 3986e4fdb5cSAndrew Turner if ((flags & SYMLOOK_IFUNC) == 0) { 3996e4fdb5cSAndrew Turner obj->non_plt_gnu_ifunc = true; 4006e4fdb5cSAndrew Turner continue; 4016e4fdb5cSAndrew Turner } 4026e4fdb5cSAndrew Turner symval = (Elf_Addr)rtld_resolve_ifunc( 4036e4fdb5cSAndrew Turner defobj, def); 4046e4fdb5cSAndrew Turner break; 4056e4fdb5cSAndrew Turner default: 4066e4fdb5cSAndrew Turner _rtld_error("%s: IFUNC for TLS reloc", 4076e4fdb5cSAndrew Turner obj->path); 4086e4fdb5cSAndrew Turner return (-1); 4096e4fdb5cSAndrew Turner } 4106e4fdb5cSAndrew Turner } else { 4116e4fdb5cSAndrew Turner if ((flags & SYMLOOK_IFUNC) != 0) 4126e4fdb5cSAndrew Turner continue; 4136e4fdb5cSAndrew Turner symval = (Elf_Addr)defobj->relocbase + 4146e4fdb5cSAndrew Turner def->st_value; 4156e4fdb5cSAndrew Turner } 4166e4fdb5cSAndrew Turner break; 4176e4fdb5cSAndrew Turner default: 4186e4fdb5cSAndrew Turner if ((flags & SYMLOOK_IFUNC) != 0) 4196e4fdb5cSAndrew Turner continue; 4206e4fdb5cSAndrew Turner } 4216e4fdb5cSAndrew Turner 422047c6e3aSAndrew Turner where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 423047c6e3aSAndrew Turner 424047c6e3aSAndrew Turner switch (ELF_R_TYPE(rela->r_info)) { 425047c6e3aSAndrew Turner case R_AARCH64_ABS64: 426047c6e3aSAndrew Turner case R_AARCH64_GLOB_DAT: 4276e4fdb5cSAndrew Turner *where = symval + rela->r_addend; 428047c6e3aSAndrew Turner break; 429047c6e3aSAndrew Turner case R_AARCH64_COPY: 430047c6e3aSAndrew Turner /* 431047c6e3aSAndrew Turner * These are deferred until all other relocations have 432047c6e3aSAndrew Turner * been done. All we do here is make sure that the 433047c6e3aSAndrew Turner * COPY relocation is not in a shared library. They 434047c6e3aSAndrew Turner * are allowed only in executable files. 435047c6e3aSAndrew Turner */ 436047c6e3aSAndrew Turner if (!obj->mainprog) { 437047c6e3aSAndrew Turner _rtld_error("%s: Unexpected R_AARCH64_COPY " 438047c6e3aSAndrew Turner "relocation in shared library", obj->path); 439047c6e3aSAndrew Turner return (-1); 440047c6e3aSAndrew Turner } 441047c6e3aSAndrew Turner break; 44202dbdb16SAndrew Turner case R_AARCH64_TLSDESC: 443*4849c3a5SMichal Meloun reloc_tlsdesc(obj, rela, where, flags, lockstate); 44402dbdb16SAndrew Turner break; 445a97120d6SAndrew Turner case R_AARCH64_TLS_TPREL64: 446a97120d6SAndrew Turner /* 447a97120d6SAndrew Turner * We lazily allocate offsets for static TLS as we 448a97120d6SAndrew Turner * see the first relocation that references the 449a97120d6SAndrew Turner * TLS block. This allows us to support (small 450a97120d6SAndrew Turner * amounts of) static TLS in dynamically loaded 451a97120d6SAndrew Turner * modules. If we run out of space, we generate an 452a97120d6SAndrew Turner * error. 453a97120d6SAndrew Turner */ 454a97120d6SAndrew Turner if (!defobj->tls_done) { 455903e0ffdSAlex Richardson if (!allocate_tls_offset( 456903e0ffdSAlex Richardson __DECONST(Obj_Entry *, defobj))) { 457a97120d6SAndrew Turner _rtld_error( 458a97120d6SAndrew Turner "%s: No space available for static " 459a97120d6SAndrew Turner "Thread Local Storage", obj->path); 460a97120d6SAndrew Turner return (-1); 461a97120d6SAndrew Turner } 462a97120d6SAndrew Turner } 463*4849c3a5SMichal Meloun /* Test weak undefined thread variable */ 464*4849c3a5SMichal Meloun if (def->st_shndx != SHN_UNDEF) { 465a97120d6SAndrew Turner *where = def->st_value + rela->r_addend + 4667c812942SAndrew Turner defobj->tlsoffset; 467*4849c3a5SMichal Meloun } else { 468*4849c3a5SMichal Meloun /* 469*4849c3a5SMichal Meloun * XXX We should relocate undefined thread 470*4849c3a5SMichal Meloun * weak variable address to NULL, but how? 471*4849c3a5SMichal Meloun * Can we return error in this situation? 472*4849c3a5SMichal Meloun */ 473*4849c3a5SMichal Meloun rtld_printf("%s: Unable to relocate undefined " 474*4849c3a5SMichal Meloun "weak TLS variable\n", obj->path); 475*4849c3a5SMichal Meloun #if 0 476*4849c3a5SMichal Meloun return (-1); 477*4849c3a5SMichal Meloun #else 478*4849c3a5SMichal Meloun *where = def->st_value + rela->r_addend + 479*4849c3a5SMichal Meloun defobj->tlsoffset; 480*4849c3a5SMichal Meloun #endif 481*4849c3a5SMichal Meloun } 482a97120d6SAndrew Turner break; 48363003c4bSMichal Meloun 48463003c4bSMichal Meloun /* 48563003c4bSMichal Meloun * !!! BEWARE !!! 48663003c4bSMichal Meloun * ARM ELF ABI defines TLS_DTPMOD64 as 1029, and TLS_DTPREL64 48763003c4bSMichal Meloun * as 1028. But actual bfd linker and the glibc RTLD linker 48863003c4bSMichal Meloun * treats TLS_DTPMOD64 as 1028 and TLS_DTPREL64 1029. 48963003c4bSMichal Meloun */ 49063003c4bSMichal Meloun case R_AARCH64_TLS_DTPREL64: /* efectively is TLS_DTPMOD64 */ 49163003c4bSMichal Meloun *where += (Elf_Addr)defobj->tlsindex; 49263003c4bSMichal Meloun break; 49363003c4bSMichal Meloun case R_AARCH64_TLS_DTPMOD64: /* efectively is TLS_DTPREL64 */ 49463003c4bSMichal Meloun *where += (Elf_Addr)(def->st_value + rela->r_addend); 49563003c4bSMichal Meloun break; 496047c6e3aSAndrew Turner case R_AARCH64_RELATIVE: 497047c6e3aSAndrew Turner *where = (Elf_Addr)(obj->relocbase + rela->r_addend); 498047c6e3aSAndrew Turner break; 49963003c4bSMichal Meloun case R_AARCH64_NONE: 50063003c4bSMichal Meloun break; 501047c6e3aSAndrew Turner default: 502047c6e3aSAndrew Turner rtld_printf("%s: Unhandled relocation %lu\n", 503047c6e3aSAndrew Turner obj->path, ELF_R_TYPE(rela->r_info)); 504047c6e3aSAndrew Turner return (-1); 505047c6e3aSAndrew Turner } 506047c6e3aSAndrew Turner } 507047c6e3aSAndrew Turner 508047c6e3aSAndrew Turner return (0); 509047c6e3aSAndrew Turner } 510047c6e3aSAndrew Turner 511047c6e3aSAndrew Turner void 512047c6e3aSAndrew Turner allocate_initial_tls(Obj_Entry *objs) 513047c6e3aSAndrew Turner { 514047c6e3aSAndrew Turner Elf_Addr **tp; 515047c6e3aSAndrew Turner 516047c6e3aSAndrew Turner /* 517047c6e3aSAndrew Turner * Fix the size of the static TLS block by using the maximum 518047c6e3aSAndrew Turner * offset allocated so far and adding a bit for dynamic modules to 519047c6e3aSAndrew Turner * use. 520047c6e3aSAndrew Turner */ 521047c6e3aSAndrew Turner tls_static_space = tls_last_offset + tls_last_size + 522047c6e3aSAndrew Turner RTLD_STATIC_TLS_EXTRA; 523047c6e3aSAndrew Turner 524047c6e3aSAndrew Turner tp = (Elf_Addr **) allocate_tls(objs, NULL, TLS_TCB_SIZE, 16); 525047c6e3aSAndrew Turner 526047c6e3aSAndrew Turner asm volatile("msr tpidr_el0, %0" : : "r"(tp)); 527047c6e3aSAndrew Turner } 52822e9ff95SMichal Meloun 52922e9ff95SMichal Meloun void * 53022e9ff95SMichal Meloun __tls_get_addr(tls_index* ti) 53122e9ff95SMichal Meloun { 53222e9ff95SMichal Meloun char *p; 53322e9ff95SMichal Meloun void *_tp; 53422e9ff95SMichal Meloun 53522e9ff95SMichal Meloun __asm __volatile("mrs %0, tpidr_el0" : "=r" (_tp)); 53622e9ff95SMichal Meloun p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset); 53722e9ff95SMichal Meloun 53822e9ff95SMichal Meloun return (p); 53922e9ff95SMichal Meloun } 540