127bd4146SNathan Whitehorn /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 227bd4146SNathan Whitehorn 327bd4146SNathan Whitehorn /*- 4e6209940SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5e6209940SPedro F. Giffuni * 627bd4146SNathan Whitehorn * Copyright (C) 1998 Tsubai Masanari 727bd4146SNathan Whitehorn * All rights reserved. 827bd4146SNathan Whitehorn * 927bd4146SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 1027bd4146SNathan Whitehorn * modification, are permitted provided that the following conditions 1127bd4146SNathan Whitehorn * are met: 1227bd4146SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 1327bd4146SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 1427bd4146SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 1527bd4146SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 1627bd4146SNathan Whitehorn * documentation and/or other materials provided with the distribution. 1727bd4146SNathan Whitehorn * 3. The name of the author may not be used to endorse or promote products 1827bd4146SNathan Whitehorn * derived from this software without specific prior written permission. 1927bd4146SNathan Whitehorn * 2027bd4146SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2127bd4146SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2227bd4146SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2327bd4146SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2427bd4146SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2527bd4146SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2627bd4146SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2727bd4146SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2827bd4146SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2927bd4146SNathan Whitehorn * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3027bd4146SNathan Whitehorn * 3127bd4146SNathan Whitehorn * $FreeBSD$ 3227bd4146SNathan Whitehorn */ 3327bd4146SNathan Whitehorn 3427bd4146SNathan Whitehorn #include <sys/param.h> 3527bd4146SNathan Whitehorn #include <sys/mman.h> 36*41b4ec8aSBrandon Bergren #include <sys/sysctl.h> 3727bd4146SNathan Whitehorn 3827bd4146SNathan Whitehorn #include <errno.h> 3927bd4146SNathan Whitehorn #include <stdio.h> 4027bd4146SNathan Whitehorn #include <stdlib.h> 4127bd4146SNathan Whitehorn #include <string.h> 4227bd4146SNathan Whitehorn #include <unistd.h> 43a29cc9a3SAndriy Gapon #include <machine/cpu.h> 4427bd4146SNathan Whitehorn #include <machine/md_var.h> 4527bd4146SNathan Whitehorn 4627bd4146SNathan Whitehorn #include "debug.h" 4727bd4146SNathan Whitehorn #include "rtld.h" 4827bd4146SNathan Whitehorn 4929ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 5027bd4146SNathan Whitehorn struct funcdesc { 5127bd4146SNathan Whitehorn Elf_Addr addr; 5227bd4146SNathan Whitehorn Elf_Addr toc; 5327bd4146SNathan Whitehorn Elf_Addr env; 5427bd4146SNathan Whitehorn }; 5529ba9b61SNathan Whitehorn #endif 5627bd4146SNathan Whitehorn 5727bd4146SNathan Whitehorn /* 5827bd4146SNathan Whitehorn * Process the R_PPC_COPY relocations 5927bd4146SNathan Whitehorn */ 6027bd4146SNathan Whitehorn int 6127bd4146SNathan Whitehorn do_copy_relocations(Obj_Entry *dstobj) 6227bd4146SNathan Whitehorn { 6327bd4146SNathan Whitehorn const Elf_Rela *relalim; 6427bd4146SNathan Whitehorn const Elf_Rela *rela; 6527bd4146SNathan Whitehorn 6627bd4146SNathan Whitehorn /* 6727bd4146SNathan Whitehorn * COPY relocs are invalid outside of the main program 6827bd4146SNathan Whitehorn */ 6927bd4146SNathan Whitehorn assert(dstobj->mainprog); 7027bd4146SNathan Whitehorn 71903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *) dstobj->rela + 7227bd4146SNathan Whitehorn dstobj->relasize); 7327bd4146SNathan Whitehorn for (rela = dstobj->rela; rela < relalim; rela++) { 7427bd4146SNathan Whitehorn void *dstaddr; 7527bd4146SNathan Whitehorn const Elf_Sym *dstsym; 7627bd4146SNathan Whitehorn const char *name; 7727bd4146SNathan Whitehorn size_t size; 7827bd4146SNathan Whitehorn const void *srcaddr; 7927bd4146SNathan Whitehorn const Elf_Sym *srcsym = NULL; 808569deafSKonstantin Belousov const Obj_Entry *srcobj, *defobj; 818569deafSKonstantin Belousov SymLook req; 828569deafSKonstantin Belousov int res; 8327bd4146SNathan Whitehorn 8427bd4146SNathan Whitehorn if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 8527bd4146SNathan Whitehorn continue; 8627bd4146SNathan Whitehorn } 8727bd4146SNathan Whitehorn 8827bd4146SNathan Whitehorn dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 8927bd4146SNathan Whitehorn dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 9027bd4146SNathan Whitehorn name = dstobj->strtab + dstsym->st_name; 9127bd4146SNathan Whitehorn size = dstsym->st_size; 928569deafSKonstantin Belousov symlook_init(&req, name); 938569deafSKonstantin Belousov req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 94082f959aSKonstantin Belousov req.flags = SYMLOOK_EARLY; 9527bd4146SNathan Whitehorn 969fee0541SKonstantin Belousov for (srcobj = globallist_next(dstobj); srcobj != NULL; 979fee0541SKonstantin Belousov srcobj = globallist_next(srcobj)) { 988569deafSKonstantin Belousov res = symlook_obj(&req, srcobj); 998569deafSKonstantin Belousov if (res == 0) { 1008569deafSKonstantin Belousov srcsym = req.sym_out; 1018569deafSKonstantin Belousov defobj = req.defobj_out; 10227bd4146SNathan Whitehorn break; 10327bd4146SNathan Whitehorn } 10427bd4146SNathan Whitehorn } 10527bd4146SNathan Whitehorn 10627bd4146SNathan Whitehorn if (srcobj == NULL) { 10727bd4146SNathan Whitehorn _rtld_error("Undefined symbol \"%s\" " 10827bd4146SNathan Whitehorn " referenced from COPY" 10927bd4146SNathan Whitehorn " relocation in %s", name, dstobj->path); 11027bd4146SNathan Whitehorn return (-1); 11127bd4146SNathan Whitehorn } 11227bd4146SNathan Whitehorn 1138569deafSKonstantin Belousov srcaddr = (const void *)(defobj->relocbase+srcsym->st_value); 11427bd4146SNathan Whitehorn memcpy(dstaddr, srcaddr, size); 11527bd4146SNathan Whitehorn dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); 11627bd4146SNathan Whitehorn } 11727bd4146SNathan Whitehorn 11827bd4146SNathan Whitehorn return (0); 11927bd4146SNathan Whitehorn } 12027bd4146SNathan Whitehorn 12127bd4146SNathan Whitehorn 12227bd4146SNathan Whitehorn /* 12327bd4146SNathan Whitehorn * Perform early relocation of the run-time linker image 12427bd4146SNathan Whitehorn */ 12527bd4146SNathan Whitehorn void 12627bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 12727bd4146SNathan Whitehorn { 128a5d5e8ddSPedro F. Giffuni const Elf_Rela *rela = NULL, *relalim; 12927bd4146SNathan Whitehorn Elf_Addr relasz = 0; 13027bd4146SNathan Whitehorn Elf_Addr *where; 13127bd4146SNathan Whitehorn 13227bd4146SNathan Whitehorn /* 13327bd4146SNathan Whitehorn * Extract the rela/relasz values from the dynamic section 13427bd4146SNathan Whitehorn */ 13527bd4146SNathan Whitehorn for (; dynp->d_tag != DT_NULL; dynp++) { 13627bd4146SNathan Whitehorn switch (dynp->d_tag) { 13727bd4146SNathan Whitehorn case DT_RELA: 13827bd4146SNathan Whitehorn rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 13927bd4146SNathan Whitehorn break; 14027bd4146SNathan Whitehorn case DT_RELASZ: 14127bd4146SNathan Whitehorn relasz = dynp->d_un.d_val; 14227bd4146SNathan Whitehorn break; 14327bd4146SNathan Whitehorn } 14427bd4146SNathan Whitehorn } 14527bd4146SNathan Whitehorn 14627bd4146SNathan Whitehorn /* 14727bd4146SNathan Whitehorn * Relocate these values 14827bd4146SNathan Whitehorn */ 149903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)rela + relasz); 15027bd4146SNathan Whitehorn for (; rela < relalim; rela++) { 15127bd4146SNathan Whitehorn where = (Elf_Addr *)(relocbase + rela->r_offset); 15227bd4146SNathan Whitehorn *where = (Elf_Addr)(relocbase + rela->r_addend); 15327bd4146SNathan Whitehorn } 15427bd4146SNathan Whitehorn } 15527bd4146SNathan Whitehorn 15627bd4146SNathan Whitehorn 15727bd4146SNathan Whitehorn /* 15827bd4146SNathan Whitehorn * Relocate a non-PLT object with addend. 15927bd4146SNathan Whitehorn */ 16027bd4146SNathan Whitehorn static int 161903e0ffdSAlex Richardson reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, 162903e0ffdSAlex Richardson const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate) 16327bd4146SNathan Whitehorn { 164*41b4ec8aSBrandon Bergren const Elf_Sym *def = NULL; 16527bd4146SNathan Whitehorn const Obj_Entry *defobj; 166*41b4ec8aSBrandon Bergren Elf_Addr *where, symval = 0; 16727bd4146SNathan Whitehorn 168*41b4ec8aSBrandon Bergren /* 169*41b4ec8aSBrandon Bergren * First, resolve symbol for relocations which 170*41b4ec8aSBrandon Bergren * reference symbols. 171*41b4ec8aSBrandon Bergren */ 17227bd4146SNathan Whitehorn switch (ELF_R_TYPE(rela->r_info)) { 17327bd4146SNathan Whitehorn 1749cc92083SNathan Whitehorn case R_PPC64_UADDR64: /* doubleword64 S + A */ 1759cc92083SNathan Whitehorn case R_PPC64_ADDR64: 17627bd4146SNathan Whitehorn case R_PPC_GLOB_DAT: 177*41b4ec8aSBrandon Bergren case R_PPC64_DTPMOD64: 178*41b4ec8aSBrandon Bergren case R_PPC64_TPREL64: 179*41b4ec8aSBrandon Bergren case R_PPC64_DTPREL64: 18027bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 181082f959aSKonstantin Belousov flags, cache, lockstate); 18227bd4146SNathan Whitehorn if (def == NULL) { 18327bd4146SNathan Whitehorn return (-1); 18427bd4146SNathan Whitehorn } 18527bd4146SNathan Whitehorn /* 186*41b4ec8aSBrandon Bergren * If symbol is IFUNC, only perform relocation 187*41b4ec8aSBrandon Bergren * when caller allowed it by passing 188*41b4ec8aSBrandon Bergren * SYMLOOK_IFUNC flag. Skip the relocations 189*41b4ec8aSBrandon Bergren * otherwise. 190*41b4ec8aSBrandon Bergren * 191*41b4ec8aSBrandon Bergren * Also error out in case IFUNC relocations 192*41b4ec8aSBrandon Bergren * are specified for TLS, which cannot be 193*41b4ec8aSBrandon Bergren * usefully interpreted. 19427bd4146SNathan Whitehorn */ 195*41b4ec8aSBrandon Bergren if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 196*41b4ec8aSBrandon Bergren switch (ELF_R_TYPE(rela->r_info)) { 197*41b4ec8aSBrandon Bergren case R_PPC64_UADDR64: 198*41b4ec8aSBrandon Bergren case R_PPC64_ADDR64: 199*41b4ec8aSBrandon Bergren case R_PPC_GLOB_DAT: 200*41b4ec8aSBrandon Bergren if ((flags & SYMLOOK_IFUNC) == 0) { 201*41b4ec8aSBrandon Bergren dbg("Non-PLT reference to IFUNC found!"); 202*41b4ec8aSBrandon Bergren obj->non_plt_gnu_ifunc = true; 203*41b4ec8aSBrandon Bergren return (0); 204*41b4ec8aSBrandon Bergren } 205*41b4ec8aSBrandon Bergren symval = (Elf_Addr)rtld_resolve_ifunc( 206*41b4ec8aSBrandon Bergren defobj, def); 207*41b4ec8aSBrandon Bergren break; 208*41b4ec8aSBrandon Bergren default: 209*41b4ec8aSBrandon Bergren _rtld_error("%s: IFUNC for TLS reloc", 21027bd4146SNathan Whitehorn obj->path); 21127bd4146SNathan Whitehorn return (-1); 21227bd4146SNathan Whitehorn } 213*41b4ec8aSBrandon Bergren } else { 214*41b4ec8aSBrandon Bergren if ((flags & SYMLOOK_IFUNC) != 0) 215*41b4ec8aSBrandon Bergren return (0); 216*41b4ec8aSBrandon Bergren symval = (Elf_Addr)defobj->relocbase + 217*41b4ec8aSBrandon Bergren def->st_value; 218*41b4ec8aSBrandon Bergren } 21927bd4146SNathan Whitehorn break; 220*41b4ec8aSBrandon Bergren default: 221*41b4ec8aSBrandon Bergren if ((flags & SYMLOOK_IFUNC) != 0) 222*41b4ec8aSBrandon Bergren return (0); 223*41b4ec8aSBrandon Bergren } 22427bd4146SNathan Whitehorn 225*41b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 226*41b4ec8aSBrandon Bergren 227*41b4ec8aSBrandon Bergren switch (ELF_R_TYPE(rela->r_info)) { 228*41b4ec8aSBrandon Bergren case R_PPC_NONE: 22927bd4146SNathan Whitehorn break; 230*41b4ec8aSBrandon Bergren case R_PPC64_UADDR64: 231*41b4ec8aSBrandon Bergren case R_PPC64_ADDR64: 232*41b4ec8aSBrandon Bergren case R_PPC_GLOB_DAT: 233*41b4ec8aSBrandon Bergren /* Don't issue write if unnecessary; avoid COW page fault */ 234*41b4ec8aSBrandon Bergren if (*where != symval + rela->r_addend) { 235*41b4ec8aSBrandon Bergren *where = symval + rela->r_addend; 236*41b4ec8aSBrandon Bergren } 237*41b4ec8aSBrandon Bergren break; 23827bd4146SNathan Whitehorn case R_PPC64_DTPMOD64: 23927bd4146SNathan Whitehorn *where = (Elf_Addr) defobj->tlsindex; 24027bd4146SNathan Whitehorn break; 24127bd4146SNathan Whitehorn case R_PPC64_TPREL64: 24227bd4146SNathan Whitehorn /* 24327bd4146SNathan Whitehorn * We lazily allocate offsets for static TLS as we 24427bd4146SNathan Whitehorn * see the first relocation that references the 24527bd4146SNathan Whitehorn * TLS block. This allows us to support (small 24627bd4146SNathan Whitehorn * amounts of) static TLS in dynamically loaded 24727bd4146SNathan Whitehorn * modules. If we run out of space, we generate an 24827bd4146SNathan Whitehorn * error. 24927bd4146SNathan Whitehorn */ 25027bd4146SNathan Whitehorn if (!defobj->tls_done) { 251903e0ffdSAlex Richardson if (!allocate_tls_offset( 252903e0ffdSAlex Richardson __DECONST(Obj_Entry *, defobj))) { 25327bd4146SNathan Whitehorn _rtld_error("%s: No space available for static " 25427bd4146SNathan Whitehorn "Thread Local Storage", obj->path); 25527bd4146SNathan Whitehorn return (-1); 25627bd4146SNathan Whitehorn } 25727bd4146SNathan Whitehorn } 25827bd4146SNathan Whitehorn 25927bd4146SNathan Whitehorn *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 26027bd4146SNathan Whitehorn + (Elf_Addr *)(def->st_value + rela->r_addend 26145a18a1fSJustin Hibbits + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE); 26227bd4146SNathan Whitehorn break; 26327bd4146SNathan Whitehorn case R_PPC64_DTPREL64: 26427bd4146SNathan Whitehorn *where += (Elf_Addr)(def->st_value + rela->r_addend 26527bd4146SNathan Whitehorn - TLS_DTV_OFFSET); 266*41b4ec8aSBrandon Bergren break; 267*41b4ec8aSBrandon Bergren case R_PPC_RELATIVE: /* doubleword64 B + A */ 268*41b4ec8aSBrandon Bergren symval = (Elf_Addr)(obj->relocbase + rela->r_addend); 26927bd4146SNathan Whitehorn 270*41b4ec8aSBrandon Bergren /* As above, don't issue write unnecessarily */ 271*41b4ec8aSBrandon Bergren if (*where != symval) { 272*41b4ec8aSBrandon Bergren *where = symval; 273*41b4ec8aSBrandon Bergren } 274*41b4ec8aSBrandon Bergren break; 275*41b4ec8aSBrandon Bergren case R_PPC_COPY: 276*41b4ec8aSBrandon Bergren /* 277*41b4ec8aSBrandon Bergren * These are deferred until all other relocations 278*41b4ec8aSBrandon Bergren * have been done. All we do here is make sure 279*41b4ec8aSBrandon Bergren * that the COPY relocation is not in a shared 280*41b4ec8aSBrandon Bergren * library. They are allowed only in executable 281*41b4ec8aSBrandon Bergren * files. 282*41b4ec8aSBrandon Bergren */ 283*41b4ec8aSBrandon Bergren if (!obj->mainprog) { 284*41b4ec8aSBrandon Bergren _rtld_error("%s: Unexpected R_COPY " 285*41b4ec8aSBrandon Bergren " relocation in shared library", 286*41b4ec8aSBrandon Bergren obj->path); 287*41b4ec8aSBrandon Bergren return (-1); 288*41b4ec8aSBrandon Bergren } 289*41b4ec8aSBrandon Bergren break; 290*41b4ec8aSBrandon Bergren case R_PPC_IRELATIVE: 291*41b4ec8aSBrandon Bergren /* 292*41b4ec8aSBrandon Bergren * These will be handled by reloc_iresolve(). 293*41b4ec8aSBrandon Bergren */ 294*41b4ec8aSBrandon Bergren obj->irelative = true; 295*41b4ec8aSBrandon Bergren break; 296*41b4ec8aSBrandon Bergren case R_PPC_JMP_SLOT: 297*41b4ec8aSBrandon Bergren /* 298*41b4ec8aSBrandon Bergren * These will be handled by the plt/jmpslot routines 299*41b4ec8aSBrandon Bergren */ 30027bd4146SNathan Whitehorn break; 30127bd4146SNathan Whitehorn 30227bd4146SNathan Whitehorn default: 30327bd4146SNathan Whitehorn _rtld_error("%s: Unsupported relocation type %ld" 30427bd4146SNathan Whitehorn " in non-PLT relocations\n", obj->path, 30527bd4146SNathan Whitehorn ELF_R_TYPE(rela->r_info)); 30627bd4146SNathan Whitehorn return (-1); 30727bd4146SNathan Whitehorn } 30827bd4146SNathan Whitehorn return (0); 30927bd4146SNathan Whitehorn } 31027bd4146SNathan Whitehorn 31127bd4146SNathan Whitehorn 31227bd4146SNathan Whitehorn /* 31327bd4146SNathan Whitehorn * Process non-PLT relocations 31427bd4146SNathan Whitehorn */ 31527bd4146SNathan Whitehorn int 316082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 317082f959aSKonstantin Belousov RtldLockState *lockstate) 31827bd4146SNathan Whitehorn { 31927bd4146SNathan Whitehorn const Elf_Rela *relalim; 32027bd4146SNathan Whitehorn const Elf_Rela *rela; 321f846c80aSKonstantin Belousov const Elf_Phdr *phdr; 32227bd4146SNathan Whitehorn SymCache *cache; 323f6265192SKonstantin Belousov int bytes = obj->dynsymcount * sizeof(SymCache); 32427bd4146SNathan Whitehorn int r = -1; 32527bd4146SNathan Whitehorn 32627bd4146SNathan Whitehorn /* 32727bd4146SNathan Whitehorn * The dynamic loader may be called from a thread, we have 32827bd4146SNathan Whitehorn * limited amounts of stack available so we cannot use alloca(). 32927bd4146SNathan Whitehorn */ 33027bd4146SNathan Whitehorn if (obj != obj_rtld) { 33127bd4146SNathan Whitehorn cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 33227bd4146SNathan Whitehorn -1, 0); 33327bd4146SNathan Whitehorn if (cache == MAP_FAILED) 33427bd4146SNathan Whitehorn cache = NULL; 33527bd4146SNathan Whitehorn } else 33627bd4146SNathan Whitehorn cache = NULL; 33727bd4146SNathan Whitehorn 33827bd4146SNathan Whitehorn /* 33927bd4146SNathan Whitehorn * From the SVR4 PPC ABI: 34027bd4146SNathan Whitehorn * "The PowerPC family uses only the Elf32_Rela relocation 34127bd4146SNathan Whitehorn * entries with explicit addends." 34227bd4146SNathan Whitehorn */ 343903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 34427bd4146SNathan Whitehorn for (rela = obj->rela; rela < relalim; rela++) { 345082f959aSKonstantin Belousov if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, 346082f959aSKonstantin Belousov lockstate) < 0) 34727bd4146SNathan Whitehorn goto done; 34827bd4146SNathan Whitehorn } 34927bd4146SNathan Whitehorn r = 0; 35027bd4146SNathan Whitehorn done: 3514b51c699SNathan Whitehorn if (cache) 35227bd4146SNathan Whitehorn munmap(cache, bytes); 3534b51c699SNathan Whitehorn 354f846c80aSKonstantin Belousov /* 355f846c80aSKonstantin Belousov * Synchronize icache for executable segments in case we made 356f846c80aSKonstantin Belousov * any changes. 357f846c80aSKonstantin Belousov */ 358f846c80aSKonstantin Belousov for (phdr = obj->phdr; 359f846c80aSKonstantin Belousov (const char *)phdr < (const char *)obj->phdr + obj->phsize; 360f846c80aSKonstantin Belousov phdr++) { 361f846c80aSKonstantin Belousov if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) { 362f846c80aSKonstantin Belousov __syncicache(obj->relocbase + phdr->p_vaddr, 363f846c80aSKonstantin Belousov phdr->p_memsz); 364f846c80aSKonstantin Belousov } 365f846c80aSKonstantin Belousov } 3664b51c699SNathan Whitehorn 36727bd4146SNathan Whitehorn return (r); 36827bd4146SNathan Whitehorn } 36927bd4146SNathan Whitehorn 37027bd4146SNathan Whitehorn 37127bd4146SNathan Whitehorn /* 37227bd4146SNathan Whitehorn * Initialise a PLT slot to the resolving trampoline 37327bd4146SNathan Whitehorn */ 37427bd4146SNathan Whitehorn static int 37527bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 37627bd4146SNathan Whitehorn { 37727bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 37827bd4146SNathan Whitehorn long reloff; 37927bd4146SNathan Whitehorn 38027bd4146SNathan Whitehorn reloff = rela - obj->pltrela; 38127bd4146SNathan Whitehorn 382a4c5dfc0SNathan Whitehorn dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, 383a4c5dfc0SNathan Whitehorn reloff, obj->glink); 384a4c5dfc0SNathan Whitehorn 38529ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 386a4c5dfc0SNathan Whitehorn /* Glink code is 3 instructions after the first 32k, 2 before */ 387a4c5dfc0SNathan Whitehorn *where = (Elf_Addr)obj->glink + 32 + 388a4c5dfc0SNathan Whitehorn 8*((reloff < 0x8000) ? reloff : 0x8000) + 389a4c5dfc0SNathan Whitehorn 12*((reloff < 0x8000) ? 0 : (reloff - 0x8000)); 39029ba9b61SNathan Whitehorn #else 391*41b4ec8aSBrandon Bergren /* 64-Bit ELF V2 ABI Specification, sec. 4.2.5.3. */ 39229ba9b61SNathan Whitehorn *where = (Elf_Addr)obj->glink + 4*reloff + 32; 39329ba9b61SNathan Whitehorn #endif 39427bd4146SNathan Whitehorn 39527bd4146SNathan Whitehorn return (0); 39627bd4146SNathan Whitehorn } 39727bd4146SNathan Whitehorn 39827bd4146SNathan Whitehorn /* 39927bd4146SNathan Whitehorn * Process the PLT relocations. 40027bd4146SNathan Whitehorn */ 40127bd4146SNathan Whitehorn int 4024849c3a5SMichal Meloun reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused) 40327bd4146SNathan Whitehorn { 40427bd4146SNathan Whitehorn const Elf_Rela *relalim; 40527bd4146SNathan Whitehorn const Elf_Rela *rela; 40627bd4146SNathan Whitehorn 40727bd4146SNathan Whitehorn if (obj->pltrelasize != 0) { 408903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela + 40927bd4146SNathan Whitehorn obj->pltrelasize); 41027bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 411*41b4ec8aSBrandon Bergren 412*41b4ec8aSBrandon Bergren #if defined(_CALL_ELF) && _CALL_ELF == 2 413*41b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 414*41b4ec8aSBrandon Bergren dbg("ABI violation - found IRELATIVE in the PLT."); 415*41b4ec8aSBrandon Bergren obj->irelative = true; 416*41b4ec8aSBrandon Bergren continue; 417*41b4ec8aSBrandon Bergren } 418*41b4ec8aSBrandon Bergren #endif 419*41b4ec8aSBrandon Bergren /* 420*41b4ec8aSBrandon Bergren * PowerPC(64) .rela.plt is composed of an array of 421*41b4ec8aSBrandon Bergren * R_PPC_JMP_SLOT relocations. Unlike other platforms, 422*41b4ec8aSBrandon Bergren * this is the ONLY relocation type that is valid here. 423*41b4ec8aSBrandon Bergren */ 42427bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 42527bd4146SNathan Whitehorn 42627bd4146SNathan Whitehorn if (reloc_plt_object(obj, rela) < 0) { 42727bd4146SNathan Whitehorn return (-1); 42827bd4146SNathan Whitehorn } 42927bd4146SNathan Whitehorn } 43027bd4146SNathan Whitehorn } 43127bd4146SNathan Whitehorn 43227bd4146SNathan Whitehorn return (0); 43327bd4146SNathan Whitehorn } 43427bd4146SNathan Whitehorn 43527bd4146SNathan Whitehorn /* 43627bd4146SNathan Whitehorn * LD_BIND_NOW was set - force relocation for all jump slots 43727bd4146SNathan Whitehorn */ 43827bd4146SNathan Whitehorn int 439082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 44027bd4146SNathan Whitehorn { 44127bd4146SNathan Whitehorn const Obj_Entry *defobj; 44227bd4146SNathan Whitehorn const Elf_Rela *relalim; 44327bd4146SNathan Whitehorn const Elf_Rela *rela; 44427bd4146SNathan Whitehorn const Elf_Sym *def; 44527bd4146SNathan Whitehorn Elf_Addr *where; 44627bd4146SNathan Whitehorn Elf_Addr target; 44727bd4146SNathan Whitehorn 448903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela + 449903e0ffdSAlex Richardson obj->pltrelasize); 45027bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 451*41b4ec8aSBrandon Bergren /* This isn't actually a jump slot, ignore it. */ 452*41b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) 453*41b4ec8aSBrandon Bergren continue; 45427bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 45527bd4146SNathan Whitehorn where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 45627bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 457082f959aSKonstantin Belousov SYMLOOK_IN_PLT | flags, NULL, lockstate); 45827bd4146SNathan Whitehorn if (def == NULL) { 45927bd4146SNathan Whitehorn dbg("reloc_jmpslots: sym not found"); 46027bd4146SNathan Whitehorn return (-1); 46127bd4146SNathan Whitehorn } 46227bd4146SNathan Whitehorn 46327bd4146SNathan Whitehorn target = (Elf_Addr)(defobj->relocbase + def->st_value); 46427bd4146SNathan Whitehorn 465d48dde6fSNathan Whitehorn if (def == &sym_zero) { 466d48dde6fSNathan Whitehorn /* Zero undefined weak symbols */ 46729ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 468d48dde6fSNathan Whitehorn bzero(where, sizeof(struct funcdesc)); 46929ba9b61SNathan Whitehorn #else 47029ba9b61SNathan Whitehorn *where = 0; 47129ba9b61SNathan Whitehorn #endif 472d48dde6fSNathan Whitehorn } else { 473*41b4ec8aSBrandon Bergren if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 474*41b4ec8aSBrandon Bergren /* LD_BIND_NOW, ifunc in shared lib.*/ 475*41b4ec8aSBrandon Bergren obj->gnu_ifunc = true; 476*41b4ec8aSBrandon Bergren continue; 477*41b4ec8aSBrandon Bergren } 47827bd4146SNathan Whitehorn reloc_jmpslot(where, target, defobj, obj, 47927bd4146SNathan Whitehorn (const Elf_Rel *) rela); 48027bd4146SNathan Whitehorn } 481d48dde6fSNathan Whitehorn } 48227bd4146SNathan Whitehorn 48327bd4146SNathan Whitehorn obj->jmpslots_done = true; 48427bd4146SNathan Whitehorn 48527bd4146SNathan Whitehorn return (0); 48627bd4146SNathan Whitehorn } 48727bd4146SNathan Whitehorn 48827bd4146SNathan Whitehorn 48927bd4146SNathan Whitehorn /* 49027bd4146SNathan Whitehorn * Update the value of a PLT jump slot. 49127bd4146SNathan Whitehorn */ 49227bd4146SNathan Whitehorn Elf_Addr 493b6abe132SJustin Hibbits reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj __unused, 494903e0ffdSAlex Richardson const Obj_Entry *obj __unused, const Elf_Rel *rel __unused) 49527bd4146SNathan Whitehorn { 49627bd4146SNathan Whitehorn 49727bd4146SNathan Whitehorn /* 49827bd4146SNathan Whitehorn * At the PLT entry pointed at by `wherep', construct 49927bd4146SNathan Whitehorn * a direct transfer to the now fully resolved function 50027bd4146SNathan Whitehorn * address. 50127bd4146SNathan Whitehorn */ 50227bd4146SNathan Whitehorn 50329ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 50429ba9b61SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", 50529ba9b61SNathan Whitehorn (void *)wherep, (void *)target, *(Elf_Addr *)target, 50629ba9b61SNathan Whitehorn (Elf_Addr)defobj->relocbase); 50729ba9b61SNathan Whitehorn 508e35ddbe4SKonstantin Belousov if (ld_bind_not) 509e35ddbe4SKonstantin Belousov goto out; 510e35ddbe4SKonstantin Belousov 511a4c5dfc0SNathan Whitehorn /* 512a4c5dfc0SNathan Whitehorn * For the trampoline, the second two elements of the function 513a4c5dfc0SNathan Whitehorn * descriptor are unused, so we are fine replacing those at any time 514a4c5dfc0SNathan Whitehorn * with the real ones with no thread safety implications. However, we 515a4c5dfc0SNathan Whitehorn * need to make sure the main entry point pointer ([0]) is seen to be 516a4c5dfc0SNathan Whitehorn * modified *after* the second two elements. This can't be done in 517a4c5dfc0SNathan Whitehorn * general, since there are no barriers in the reading code, but put in 518a4c5dfc0SNathan Whitehorn * some isyncs to at least make it a little better. 519a4c5dfc0SNathan Whitehorn */ 52027bd4146SNathan Whitehorn memcpy(wherep, (void *)target, sizeof(struct funcdesc)); 521a4c5dfc0SNathan Whitehorn wherep[2] = ((Elf_Addr *)target)[2]; 522a4c5dfc0SNathan Whitehorn wherep[1] = ((Elf_Addr *)target)[1]; 523a4c5dfc0SNathan Whitehorn __asm __volatile ("isync" : : : "memory"); 524a4c5dfc0SNathan Whitehorn wherep[0] = ((Elf_Addr *)target)[0]; 525a4c5dfc0SNathan Whitehorn __asm __volatile ("isync" : : : "memory"); 526a4c5dfc0SNathan Whitehorn 52727bd4146SNathan Whitehorn if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { 52827bd4146SNathan Whitehorn /* 529a4c5dfc0SNathan Whitehorn * It is possible (LD_BIND_NOW) that the function 53027bd4146SNathan Whitehorn * descriptor we are copying has not yet been relocated. 531a4c5dfc0SNathan Whitehorn * If this happens, fix it. Don't worry about threading in 532a4c5dfc0SNathan Whitehorn * this case since LD_BIND_NOW makes it irrelevant. 53327bd4146SNathan Whitehorn */ 53427bd4146SNathan Whitehorn 53527bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->addr += 53627bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 53727bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->toc += 53827bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 53927bd4146SNathan Whitehorn } 54029ba9b61SNathan Whitehorn #else 54129ba9b61SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, 54229ba9b61SNathan Whitehorn (void *)target); 54327bd4146SNathan Whitehorn 544*41b4ec8aSBrandon Bergren assert(target >= (Elf_Addr)defobj->relocbase); 545*41b4ec8aSBrandon Bergren 546*41b4ec8aSBrandon Bergren if (ld_bind_not) 547*41b4ec8aSBrandon Bergren goto out; 548*41b4ec8aSBrandon Bergren 549*41b4ec8aSBrandon Bergren if (*wherep != target) 55029ba9b61SNathan Whitehorn *wherep = target; 551*41b4ec8aSBrandon Bergren 55229ba9b61SNathan Whitehorn #endif 553*41b4ec8aSBrandon Bergren out: 55429ba9b61SNathan Whitehorn 55527bd4146SNathan Whitehorn return (target); 55627bd4146SNathan Whitehorn } 55727bd4146SNathan Whitehorn 5586be4b697SKonstantin Belousov int 559*41b4ec8aSBrandon Bergren reloc_iresolve(Obj_Entry *obj, 560*41b4ec8aSBrandon Bergren struct Struct_RtldLockState *lockstate) 5616be4b697SKonstantin Belousov { 562*41b4ec8aSBrandon Bergren /* 563*41b4ec8aSBrandon Bergren * Since PLT slots on PowerPC64 are always R_PPC_JMP_SLOT, 564*41b4ec8aSBrandon Bergren * R_PPC_IRELATIVE is in RELA. 565*41b4ec8aSBrandon Bergren */ 566*41b4ec8aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 567*41b4ec8aSBrandon Bergren (void)(obj); 568*41b4ec8aSBrandon Bergren (void)(lockstate); 5696be4b697SKonstantin Belousov /* XXX not implemented */ 5706be4b697SKonstantin Belousov return (0); 571*41b4ec8aSBrandon Bergren #else 572*41b4ec8aSBrandon Bergren const Elf_Rela *relalim; 573*41b4ec8aSBrandon Bergren const Elf_Rela *rela; 574*41b4ec8aSBrandon Bergren Elf_Addr *where, target, *ptr; 575*41b4ec8aSBrandon Bergren 576*41b4ec8aSBrandon Bergren if (!obj->irelative) 577*41b4ec8aSBrandon Bergren return (0); 578*41b4ec8aSBrandon Bergren 579*41b4ec8aSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 580*41b4ec8aSBrandon Bergren for (rela = obj->rela; rela < relalim; rela++) { 581*41b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 582*41b4ec8aSBrandon Bergren ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 583*41b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 584*41b4ec8aSBrandon Bergren 585*41b4ec8aSBrandon Bergren lock_release(rtld_bind_lock, lockstate); 586*41b4ec8aSBrandon Bergren target = call_ifunc_resolver(ptr); 587*41b4ec8aSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate); 588*41b4ec8aSBrandon Bergren 589*41b4ec8aSBrandon Bergren *where = target; 590*41b4ec8aSBrandon Bergren } 591*41b4ec8aSBrandon Bergren } 592*41b4ec8aSBrandon Bergren /* 593*41b4ec8aSBrandon Bergren * XXX Remove me when lld is fixed! 594*41b4ec8aSBrandon Bergren * LLD currently makes illegal relocations in the PLT. 595*41b4ec8aSBrandon Bergren */ 596*41b4ec8aSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 597*41b4ec8aSBrandon Bergren for (rela = obj->pltrela; rela < relalim; rela++) { 598*41b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 599*41b4ec8aSBrandon Bergren ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 600*41b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 601*41b4ec8aSBrandon Bergren 602*41b4ec8aSBrandon Bergren lock_release(rtld_bind_lock, lockstate); 603*41b4ec8aSBrandon Bergren target = call_ifunc_resolver(ptr); 604*41b4ec8aSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate); 605*41b4ec8aSBrandon Bergren 606*41b4ec8aSBrandon Bergren *where = target; 607*41b4ec8aSBrandon Bergren } 608*41b4ec8aSBrandon Bergren } 609*41b4ec8aSBrandon Bergren 610*41b4ec8aSBrandon Bergren obj->irelative = false; 611*41b4ec8aSBrandon Bergren return (0); 612*41b4ec8aSBrandon Bergren #endif 6136be4b697SKonstantin Belousov } 6146be4b697SKonstantin Belousov 6156be4b697SKonstantin Belousov int 616903e0ffdSAlex Richardson reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused, 617903e0ffdSAlex Richardson struct Struct_RtldLockState *lockstate __unused) 6186be4b697SKonstantin Belousov { 619*41b4ec8aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 620*41b4ec8aSBrandon Bergren _rtld_error("reloc_gnu_ifunc(): Not implemented!"); 6216be4b697SKonstantin Belousov /* XXX not implemented */ 622*41b4ec8aSBrandon Bergren return (-1); 623*41b4ec8aSBrandon Bergren #else 624*41b4ec8aSBrandon Bergren 625*41b4ec8aSBrandon Bergren const Elf_Rela *relalim; 626*41b4ec8aSBrandon Bergren const Elf_Rela *rela; 627*41b4ec8aSBrandon Bergren Elf_Addr *where, target; 628*41b4ec8aSBrandon Bergren const Elf_Sym *def; 629*41b4ec8aSBrandon Bergren const Obj_Entry *defobj; 630*41b4ec8aSBrandon Bergren 631*41b4ec8aSBrandon Bergren if (!obj->gnu_ifunc) 6326be4b697SKonstantin Belousov return (0); 633*41b4ec8aSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 634*41b4ec8aSBrandon Bergren for (rela = obj->pltrela; rela < relalim; rela++) { 635*41b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) { 636*41b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 637*41b4ec8aSBrandon Bergren def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 638*41b4ec8aSBrandon Bergren SYMLOOK_IN_PLT | flags, NULL, lockstate); 639*41b4ec8aSBrandon Bergren if (def == NULL) 640*41b4ec8aSBrandon Bergren return (-1); 641*41b4ec8aSBrandon Bergren if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 642*41b4ec8aSBrandon Bergren continue; 643*41b4ec8aSBrandon Bergren lock_release(rtld_bind_lock, lockstate); 644*41b4ec8aSBrandon Bergren target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 645*41b4ec8aSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate); 646*41b4ec8aSBrandon Bergren reloc_jmpslot(where, target, defobj, obj, 647*41b4ec8aSBrandon Bergren (const Elf_Rel *)rela); 648*41b4ec8aSBrandon Bergren } 649*41b4ec8aSBrandon Bergren } 650*41b4ec8aSBrandon Bergren obj->gnu_ifunc = false; 651*41b4ec8aSBrandon Bergren return (0); 652*41b4ec8aSBrandon Bergren #endif 6536be4b697SKonstantin Belousov } 6546be4b697SKonstantin Belousov 65527bd4146SNathan Whitehorn void 65627bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj) 65727bd4146SNathan Whitehorn { 65829ba9b61SNathan Whitehorn Elf_Addr *pltcall; 65929ba9b61SNathan Whitehorn 66029ba9b61SNathan Whitehorn pltcall = obj->pltgot; 66129ba9b61SNathan Whitehorn 66229ba9b61SNathan Whitehorn if (pltcall == NULL) { 66329ba9b61SNathan Whitehorn return; 66429ba9b61SNathan Whitehorn } 66529ba9b61SNathan Whitehorn 666a4c5dfc0SNathan Whitehorn #if defined(_CALL_ELF) && _CALL_ELF == 2 66729ba9b61SNathan Whitehorn pltcall[0] = (Elf_Addr)&_rtld_bind_start; 66829ba9b61SNathan Whitehorn pltcall[1] = (Elf_Addr)obj; 669a4c5dfc0SNathan Whitehorn #else 670a4c5dfc0SNathan Whitehorn memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc)); 671a4c5dfc0SNathan Whitehorn pltcall[2] = (Elf_Addr)obj; 67229ba9b61SNathan Whitehorn #endif 67327bd4146SNathan Whitehorn } 67427bd4146SNathan Whitehorn 675*41b4ec8aSBrandon Bergren /* 676*41b4ec8aSBrandon Bergren * Actual values are 32 bit. 677*41b4ec8aSBrandon Bergren */ 678*41b4ec8aSBrandon Bergren u_long cpu_features; 679*41b4ec8aSBrandon Bergren u_long cpu_features2; 680*41b4ec8aSBrandon Bergren 681*41b4ec8aSBrandon Bergren void 682*41b4ec8aSBrandon Bergren powerpc64_abi_variant_hook(Elf_Auxinfo** aux_info) 683*41b4ec8aSBrandon Bergren { 684*41b4ec8aSBrandon Bergren /* 685*41b4ec8aSBrandon Bergren * Since aux_info[] is easier to work with than aux, go ahead and 686*41b4ec8aSBrandon Bergren * initialize cpu_features / cpu_features2. 687*41b4ec8aSBrandon Bergren */ 688*41b4ec8aSBrandon Bergren cpu_features = -1UL; 689*41b4ec8aSBrandon Bergren cpu_features2 = -1UL; 690*41b4ec8aSBrandon Bergren if (aux_info[AT_HWCAP] != NULL) 691*41b4ec8aSBrandon Bergren cpu_features = (uint32_t)aux_info[AT_HWCAP]->a_un.a_val; 692*41b4ec8aSBrandon Bergren if (aux_info[AT_HWCAP2] != NULL) 693*41b4ec8aSBrandon Bergren cpu_features2 = (uint32_t)aux_info[AT_HWCAP2]->a_un.a_val; 694*41b4ec8aSBrandon Bergren } 695*41b4ec8aSBrandon Bergren 69627bd4146SNathan Whitehorn void 697d27078f9SKonstantin Belousov ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 6984352999eSKonstantin Belousov { 69941fc6f68SMarius Strobl 70041fc6f68SMarius Strobl } 70141fc6f68SMarius Strobl 70241fc6f68SMarius Strobl void 70341fc6f68SMarius Strobl pre_init(void) 70441fc6f68SMarius Strobl { 70541fc6f68SMarius Strobl 7064352999eSKonstantin Belousov } 7074352999eSKonstantin Belousov 7084352999eSKonstantin Belousov void 70927bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list) 71027bd4146SNathan Whitehorn { 711746ae9dfSNathan Whitehorn Elf_Addr **tp; 71227bd4146SNathan Whitehorn 71327bd4146SNathan Whitehorn /* 71427bd4146SNathan Whitehorn * Fix the size of the static TLS block by using the maximum 71527bd4146SNathan Whitehorn * offset allocated so far and adding a bit for dynamic modules to 71627bd4146SNathan Whitehorn * use. 71727bd4146SNathan Whitehorn */ 71827bd4146SNathan Whitehorn 71927bd4146SNathan Whitehorn tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 72027bd4146SNathan Whitehorn 721746ae9dfSNathan Whitehorn tp = (Elf_Addr **)((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16) 72227bd4146SNathan Whitehorn + TLS_TP_OFFSET + TLS_TCB_SIZE); 72327bd4146SNathan Whitehorn 724746ae9dfSNathan Whitehorn __asm __volatile("mr 13,%0" :: "r"(tp)); 72527bd4146SNathan Whitehorn } 72627bd4146SNathan Whitehorn 72727bd4146SNathan Whitehorn void* 72827bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti) 72927bd4146SNathan Whitehorn { 730746ae9dfSNathan Whitehorn Elf_Addr **tp; 73127bd4146SNathan Whitehorn char *p; 73227bd4146SNathan Whitehorn 733746ae9dfSNathan Whitehorn __asm __volatile("mr %0,13" : "=r"(tp)); 73427bd4146SNathan Whitehorn p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 73527bd4146SNathan Whitehorn - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); 73627bd4146SNathan Whitehorn 73727bd4146SNathan Whitehorn return (p + TLS_DTV_OFFSET); 73827bd4146SNathan Whitehorn } 739