1b9dea67fSPeter Grehan /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 2b9dea67fSPeter Grehan 3b9dea67fSPeter Grehan /*- 4b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 5e6209940SPedro F. Giffuni * 6b9dea67fSPeter Grehan * Copyright (C) 1998 Tsubai Masanari 7b9dea67fSPeter Grehan * All rights reserved. 8b9dea67fSPeter Grehan * 9b9dea67fSPeter Grehan * Redistribution and use in source and binary forms, with or without 10b9dea67fSPeter Grehan * modification, are permitted provided that the following conditions 11b9dea67fSPeter Grehan * are met: 12b9dea67fSPeter Grehan * 1. Redistributions of source code must retain the above copyright 13b9dea67fSPeter Grehan * notice, this list of conditions and the following disclaimer. 14b9dea67fSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 15b9dea67fSPeter Grehan * notice, this list of conditions and the following disclaimer in the 16b9dea67fSPeter Grehan * documentation and/or other materials provided with the distribution. 17b9dea67fSPeter Grehan * 3. The name of the author may not be used to endorse or promote products 18b9dea67fSPeter Grehan * derived from this software without specific prior written permission. 19b9dea67fSPeter Grehan * 20b9dea67fSPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21b9dea67fSPeter Grehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22b9dea67fSPeter Grehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23b9dea67fSPeter Grehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24b9dea67fSPeter Grehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25b9dea67fSPeter Grehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26b9dea67fSPeter Grehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27b9dea67fSPeter Grehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28b9dea67fSPeter Grehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29b9dea67fSPeter Grehan * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30b9dea67fSPeter Grehan */ 31b9dea67fSPeter Grehan 32b9dea67fSPeter Grehan #include <sys/param.h> 33b9dea67fSPeter Grehan #include <sys/mman.h> 34b9dea67fSPeter Grehan 35b9dea67fSPeter Grehan #include <errno.h> 36b9dea67fSPeter Grehan #include <stdio.h> 37b9dea67fSPeter Grehan #include <stdlib.h> 38b9dea67fSPeter Grehan #include <string.h> 39b9dea67fSPeter Grehan #include <unistd.h> 40a29cc9a3SAndriy Gapon #include <machine/cpu.h> 41c606eab4SNathan Whitehorn #include <machine/atomic.h> 421566f9a7SJohn Birrell #include <machine/md_var.h> 43b9dea67fSPeter Grehan 44b9dea67fSPeter Grehan #include "debug.h" 45b9dea67fSPeter Grehan #include "rtld.h" 46b9dea67fSPeter Grehan 47b9dea67fSPeter Grehan #define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \ 48b9dea67fSPeter Grehan ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) 49b9dea67fSPeter Grehan #define _ppc_la(x) ((u_int32_t)(x) & 0xffff) 50b9dea67fSPeter Grehan 514f2730f7SNathan Whitehorn #define min(a,b) (((a) < (b)) ? (a) : (b)) 524f2730f7SNathan Whitehorn #define max(a,b) (((a) > (b)) ? (a) : (b)) 534f2730f7SNathan Whitehorn 544f2730f7SNathan Whitehorn #define PLT_EXTENDED_BEGIN (1 << 13) 554f2730f7SNathan Whitehorn #define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \ 564f2730f7SNathan Whitehorn (N - PLT_EXTENDED_BEGIN)*2 : 0)) 574f2730f7SNathan Whitehorn 58f62da49bSJustin Hibbits void _rtld_bind_secureplt_start(void); 59f62da49bSJustin Hibbits 60*1cd90a2cSAndrew Turner bool 61*1cd90a2cSAndrew Turner arch_digest_dynamic(struct Struct_Obj_Entry *obj, const Elf_Dyn *dynp) 62*1cd90a2cSAndrew Turner { 63*1cd90a2cSAndrew Turner if (dynp->d_tag == DT_PPC_GOT) { 64*1cd90a2cSAndrew Turner obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr); 65*1cd90a2cSAndrew Turner return (true); 66*1cd90a2cSAndrew Turner } 67*1cd90a2cSAndrew Turner 68*1cd90a2cSAndrew Turner return (false); 69*1cd90a2cSAndrew Turner } 70*1cd90a2cSAndrew Turner 71b9dea67fSPeter Grehan /* 72b9dea67fSPeter Grehan * Process the R_PPC_COPY relocations 73b9dea67fSPeter Grehan */ 74b9dea67fSPeter Grehan int 75b9dea67fSPeter Grehan do_copy_relocations(Obj_Entry *dstobj) 76b9dea67fSPeter Grehan { 77b9dea67fSPeter Grehan const Elf_Rela *relalim; 78b9dea67fSPeter Grehan const Elf_Rela *rela; 79b9dea67fSPeter Grehan 80b9dea67fSPeter Grehan /* 81b9dea67fSPeter Grehan * COPY relocs are invalid outside of the main program 82b9dea67fSPeter Grehan */ 83b9dea67fSPeter Grehan assert(dstobj->mainprog); 84b9dea67fSPeter Grehan 85903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *) dstobj->rela + 86b9dea67fSPeter Grehan dstobj->relasize); 87b9dea67fSPeter Grehan for (rela = dstobj->rela; rela < relalim; rela++) { 88b9dea67fSPeter Grehan void *dstaddr; 89b9dea67fSPeter Grehan const Elf_Sym *dstsym; 90b9dea67fSPeter Grehan const char *name; 91b9dea67fSPeter Grehan size_t size; 92b9dea67fSPeter Grehan const void *srcaddr; 93b9dea67fSPeter Grehan const Elf_Sym *srcsym = NULL; 948569deafSKonstantin Belousov const Obj_Entry *srcobj, *defobj; 958569deafSKonstantin Belousov SymLook req; 968569deafSKonstantin Belousov int res; 97b9dea67fSPeter Grehan 98b9dea67fSPeter Grehan if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 99b9dea67fSPeter Grehan continue; 100b9dea67fSPeter Grehan } 101b9dea67fSPeter Grehan 102b9dea67fSPeter Grehan dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 103b9dea67fSPeter Grehan dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 104b9dea67fSPeter Grehan name = dstobj->strtab + dstsym->st_name; 105b9dea67fSPeter Grehan size = dstsym->st_size; 1068569deafSKonstantin Belousov symlook_init(&req, name); 1078569deafSKonstantin Belousov req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 108082f959aSKonstantin Belousov req.flags = SYMLOOK_EARLY; 109b9dea67fSPeter Grehan 1109fee0541SKonstantin Belousov for (srcobj = globallist_next(dstobj); srcobj != NULL; 1119fee0541SKonstantin Belousov srcobj = globallist_next(srcobj)) { 1128569deafSKonstantin Belousov res = symlook_obj(&req, srcobj); 1138569deafSKonstantin Belousov if (res == 0) { 1148569deafSKonstantin Belousov srcsym = req.sym_out; 1158569deafSKonstantin Belousov defobj = req.defobj_out; 116b9dea67fSPeter Grehan break; 117b9dea67fSPeter Grehan } 118b9dea67fSPeter Grehan } 119b9dea67fSPeter Grehan 120b9dea67fSPeter Grehan if (srcobj == NULL) { 121b9dea67fSPeter Grehan _rtld_error("Undefined symbol \"%s\" " 122b9dea67fSPeter Grehan " referenced from COPY" 123b9dea67fSPeter Grehan " relocation in %s", name, dstobj->path); 124b9dea67fSPeter Grehan return (-1); 125b9dea67fSPeter Grehan } 126b9dea67fSPeter Grehan 1278569deafSKonstantin Belousov srcaddr = (const void *)(defobj->relocbase+srcsym->st_value); 128b9dea67fSPeter Grehan memcpy(dstaddr, srcaddr, size); 129b9dea67fSPeter Grehan dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size); 130b9dea67fSPeter Grehan } 131b9dea67fSPeter Grehan 132b9dea67fSPeter Grehan return (0); 133b9dea67fSPeter Grehan } 134b9dea67fSPeter Grehan 135b9dea67fSPeter Grehan 136b9dea67fSPeter Grehan /* 137b9dea67fSPeter Grehan * Perform early relocation of the run-time linker image 138b9dea67fSPeter Grehan */ 139b9dea67fSPeter Grehan void 140b9dea67fSPeter Grehan reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 141b9dea67fSPeter Grehan { 142a5d5e8ddSPedro F. Giffuni const Elf_Rela *rela = NULL, *relalim; 143b9dea67fSPeter Grehan Elf_Addr relasz = 0; 144b9dea67fSPeter Grehan Elf_Addr *where; 145b9dea67fSPeter Grehan 146b9dea67fSPeter Grehan /* 147b9dea67fSPeter Grehan * Extract the rela/relasz values from the dynamic section 148b9dea67fSPeter Grehan */ 149b9dea67fSPeter Grehan for (; dynp->d_tag != DT_NULL; dynp++) { 150b9dea67fSPeter Grehan switch (dynp->d_tag) { 151b9dea67fSPeter Grehan case DT_RELA: 152b9dea67fSPeter Grehan rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 153b9dea67fSPeter Grehan break; 154b9dea67fSPeter Grehan case DT_RELASZ: 155b9dea67fSPeter Grehan relasz = dynp->d_un.d_val; 156b9dea67fSPeter Grehan break; 157b9dea67fSPeter Grehan } 158b9dea67fSPeter Grehan } 159b9dea67fSPeter Grehan 160b9dea67fSPeter Grehan /* 161b9dea67fSPeter Grehan * Relocate these values 162b9dea67fSPeter Grehan */ 163903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)rela + relasz); 164b9dea67fSPeter Grehan for (; rela < relalim; rela++) { 165b9dea67fSPeter Grehan where = (Elf_Addr *)(relocbase + rela->r_offset); 166b9dea67fSPeter Grehan *where = (Elf_Addr)(relocbase + rela->r_addend); 167b9dea67fSPeter Grehan } 168b9dea67fSPeter Grehan } 169b9dea67fSPeter Grehan 170b9dea67fSPeter Grehan 171b9dea67fSPeter Grehan /* 172b9dea67fSPeter Grehan * Relocate a non-PLT object with addend. 173b9dea67fSPeter Grehan */ 174b9dea67fSPeter Grehan static int 175903e0ffdSAlex Richardson reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, 176903e0ffdSAlex Richardson const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate) 177b9dea67fSPeter Grehan { 17857462f8fSBrandon Bergren const Elf_Sym *def = NULL; 179b9dea67fSPeter Grehan const Obj_Entry *defobj; 18057462f8fSBrandon Bergren Elf_Addr *where, symval = 0; 181b9dea67fSPeter Grehan 18257462f8fSBrandon Bergren /* 18357462f8fSBrandon Bergren * First, resolve symbol for relocations which 18457462f8fSBrandon Bergren * reference symbols. 18557462f8fSBrandon Bergren */ 186b9dea67fSPeter Grehan switch (ELF_R_TYPE(rela->r_info)) { 187b9dea67fSPeter Grehan 18857462f8fSBrandon Bergren case R_PPC_UADDR32: /* word32 S + A */ 18957462f8fSBrandon Bergren case R_PPC_ADDR32: 190b9dea67fSPeter Grehan case R_PPC_GLOB_DAT: /* word32 S + A */ 19157462f8fSBrandon Bergren case R_PPC_DTPMOD32: 19257462f8fSBrandon Bergren case R_PPC_TPREL32: 19357462f8fSBrandon Bergren case R_PPC_DTPREL32: 194b9dea67fSPeter Grehan def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 195082f959aSKonstantin Belousov flags, cache, lockstate); 196b9dea67fSPeter Grehan if (def == NULL) { 197b9dea67fSPeter Grehan return (-1); 198b9dea67fSPeter Grehan } 199b9dea67fSPeter Grehan 200b9dea67fSPeter Grehan /* 20157462f8fSBrandon Bergren * If symbol is IFUNC, only perform relocation 20257462f8fSBrandon Bergren * when caller allowed it by passing 20357462f8fSBrandon Bergren * SYMLOOK_IFUNC flag. Skip the relocations 20457462f8fSBrandon Bergren * otherwise. 20557462f8fSBrandon Bergren * 20657462f8fSBrandon Bergren * Also error out in case IFUNC relocations 20757462f8fSBrandon Bergren * are specified for TLS, which cannot be 20857462f8fSBrandon Bergren * usefully interpreted. 209b9dea67fSPeter Grehan */ 21057462f8fSBrandon Bergren if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 21157462f8fSBrandon Bergren switch (ELF_R_TYPE(rela->r_info)) { 21257462f8fSBrandon Bergren case R_PPC_UADDR32: 21357462f8fSBrandon Bergren case R_PPC_ADDR32: 21457462f8fSBrandon Bergren case R_PPC_GLOB_DAT: 21557462f8fSBrandon Bergren if ((flags & SYMLOOK_IFUNC) == 0) { 21657462f8fSBrandon Bergren dbg("Non-PLT reference to IFUNC found!"); 21757462f8fSBrandon Bergren obj->non_plt_gnu_ifunc = true; 21857462f8fSBrandon Bergren return (0); 21957462f8fSBrandon Bergren } 22057462f8fSBrandon Bergren symval = (Elf_Addr)rtld_resolve_ifunc( 22157462f8fSBrandon Bergren defobj, def); 22257462f8fSBrandon Bergren break; 22357462f8fSBrandon Bergren default: 22457462f8fSBrandon Bergren _rtld_error("%s: IFUNC for TLS reloc", 225b9dea67fSPeter Grehan obj->path); 226b9dea67fSPeter Grehan return (-1); 227b9dea67fSPeter Grehan } 22857462f8fSBrandon Bergren } else { 22957462f8fSBrandon Bergren if ((flags & SYMLOOK_IFUNC) != 0) 23057462f8fSBrandon Bergren return (0); 23157462f8fSBrandon Bergren symval = (Elf_Addr)defobj->relocbase + 23257462f8fSBrandon Bergren def->st_value; 23357462f8fSBrandon Bergren } 234b9dea67fSPeter Grehan break; 23557462f8fSBrandon Bergren default: 23657462f8fSBrandon Bergren if ((flags & SYMLOOK_IFUNC) != 0) 23757462f8fSBrandon Bergren return (0); 23857462f8fSBrandon Bergren } 23957462f8fSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 240b9dea67fSPeter Grehan 24157462f8fSBrandon Bergren switch (ELF_R_TYPE(rela->r_info)) { 24257462f8fSBrandon Bergren case R_PPC_NONE: 243b9dea67fSPeter Grehan break; 24457462f8fSBrandon Bergren case R_PPC_UADDR32: 24557462f8fSBrandon Bergren case R_PPC_ADDR32: 24657462f8fSBrandon Bergren case R_PPC_GLOB_DAT: 24757462f8fSBrandon Bergren /* Don't issue write if unnecessary; avoid COW page fault */ 24857462f8fSBrandon Bergren if (*where != symval + rela->r_addend) { 24957462f8fSBrandon Bergren *where = symval + rela->r_addend; 25057462f8fSBrandon Bergren } 25157462f8fSBrandon Bergren break; 2526c2a9753SSuleiman Souhlal case R_PPC_DTPMOD32: 2536c2a9753SSuleiman Souhlal *where = (Elf_Addr) defobj->tlsindex; 2546c2a9753SSuleiman Souhlal break; 2556c2a9753SSuleiman Souhlal case R_PPC_TPREL32: 2566c2a9753SSuleiman Souhlal /* 2576c2a9753SSuleiman Souhlal * We lazily allocate offsets for static TLS as we 2586c2a9753SSuleiman Souhlal * see the first relocation that references the 2596c2a9753SSuleiman Souhlal * TLS block. This allows us to support (small 2606c2a9753SSuleiman Souhlal * amounts of) static TLS in dynamically loaded 2616c2a9753SSuleiman Souhlal * modules. If we run out of space, we generate an 2626c2a9753SSuleiman Souhlal * error. 2636c2a9753SSuleiman Souhlal */ 264283a4f40SKonstantin Belousov if (!defobj->tls_static) { 265903e0ffdSAlex Richardson if (!allocate_tls_offset( 266903e0ffdSAlex Richardson __DECONST(Obj_Entry *, defobj))) { 2676c2a9753SSuleiman Souhlal _rtld_error("%s: No space available for static " 2686c2a9753SSuleiman Souhlal "Thread Local Storage", obj->path); 2696c2a9753SSuleiman Souhlal return (-1); 2706c2a9753SSuleiman Souhlal } 2716c2a9753SSuleiman Souhlal } 2726c2a9753SSuleiman Souhlal 2736c2a9753SSuleiman Souhlal *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 2746c2a9753SSuleiman Souhlal + (Elf_Addr *)(def->st_value + rela->r_addend 275953cba36SAndreas Tobler + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE); 2766c2a9753SSuleiman Souhlal break; 2776c2a9753SSuleiman Souhlal case R_PPC_DTPREL32: 2786c2a9753SSuleiman Souhlal *where += (Elf_Addr)(def->st_value + rela->r_addend 2796c2a9753SSuleiman Souhlal - TLS_DTV_OFFSET); 28057462f8fSBrandon Bergren break; 28157462f8fSBrandon Bergren case R_PPC_RELATIVE: /* word32 B + A */ 28257462f8fSBrandon Bergren symval = (Elf_Addr)(obj->relocbase + rela->r_addend); 2836c2a9753SSuleiman Souhlal 28457462f8fSBrandon Bergren /* As above, don't issue write unnecessarily */ 28557462f8fSBrandon Bergren if (*where != symval) { 28657462f8fSBrandon Bergren *where = symval; 28757462f8fSBrandon Bergren } 28857462f8fSBrandon Bergren break; 28957462f8fSBrandon Bergren case R_PPC_COPY: 29057462f8fSBrandon Bergren /* 29157462f8fSBrandon Bergren * These are deferred until all other relocations 29257462f8fSBrandon Bergren * have been done. All we do here is make sure 29357462f8fSBrandon Bergren * that the COPY relocation is not in a shared 29457462f8fSBrandon Bergren * library. They are allowed only in executable 29557462f8fSBrandon Bergren * files. 29657462f8fSBrandon Bergren */ 29757462f8fSBrandon Bergren if (!obj->mainprog) { 29857462f8fSBrandon Bergren _rtld_error("%s: Unexpected R_COPY " 29957462f8fSBrandon Bergren " relocation in shared library", 30057462f8fSBrandon Bergren obj->path); 30157462f8fSBrandon Bergren return (-1); 30257462f8fSBrandon Bergren } 30357462f8fSBrandon Bergren break; 30457462f8fSBrandon Bergren case R_PPC_IRELATIVE: 30557462f8fSBrandon Bergren /* 30657462f8fSBrandon Bergren * These will be handled by reloc_iresolve(). 30757462f8fSBrandon Bergren */ 30857462f8fSBrandon Bergren obj->irelative = true; 30957462f8fSBrandon Bergren break; 31057462f8fSBrandon Bergren case R_PPC_JMP_SLOT: 31157462f8fSBrandon Bergren /* 31257462f8fSBrandon Bergren * These will be handled by the plt/jmpslot routines 31357462f8fSBrandon Bergren */ 3146c2a9753SSuleiman Souhlal break; 3156c2a9753SSuleiman Souhlal 316b9dea67fSPeter Grehan default: 317b9dea67fSPeter Grehan _rtld_error("%s: Unsupported relocation type %d" 318b9dea67fSPeter Grehan " in non-PLT relocations\n", obj->path, 319b9dea67fSPeter Grehan ELF_R_TYPE(rela->r_info)); 320b9dea67fSPeter Grehan return (-1); 321b9dea67fSPeter Grehan } 322b9dea67fSPeter Grehan return (0); 323b9dea67fSPeter Grehan } 324b9dea67fSPeter Grehan 325b9dea67fSPeter Grehan 326b9dea67fSPeter Grehan /* 327b9dea67fSPeter Grehan * Process non-PLT relocations 328b9dea67fSPeter Grehan */ 329b9dea67fSPeter Grehan int 330082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 331082f959aSKonstantin Belousov RtldLockState *lockstate) 332b9dea67fSPeter Grehan { 333b9dea67fSPeter Grehan const Elf_Rela *relalim; 334b9dea67fSPeter Grehan const Elf_Rela *rela; 335f846c80aSKonstantin Belousov const Elf_Phdr *phdr; 336b9dea67fSPeter Grehan SymCache *cache; 337b9dea67fSPeter Grehan int r = -1; 338b9dea67fSPeter Grehan 339b9dea67fSPeter Grehan /* 340b9dea67fSPeter Grehan * The dynamic loader may be called from a thread, we have 341b9dea67fSPeter Grehan * limited amounts of stack available so we cannot use alloca(). 342b9dea67fSPeter Grehan */ 34399227f1eSMarcel Moolenaar if (obj != obj_rtld) { 344f6265192SKonstantin Belousov cache = calloc(obj->dynsymcount, sizeof(SymCache)); 3451dfdc15bSRoman Divacky /* No need to check for NULL here */ 34699227f1eSMarcel Moolenaar } else 34799227f1eSMarcel Moolenaar cache = NULL; 348b9dea67fSPeter Grehan 349b9dea67fSPeter Grehan /* 350b9dea67fSPeter Grehan * From the SVR4 PPC ABI: 351b9dea67fSPeter Grehan * "The PowerPC family uses only the Elf32_Rela relocation 352b9dea67fSPeter Grehan * entries with explicit addends." 353b9dea67fSPeter Grehan */ 354903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 355b9dea67fSPeter Grehan for (rela = obj->rela; rela < relalim; rela++) { 356082f959aSKonstantin Belousov if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, 357082f959aSKonstantin Belousov lockstate) < 0) 358b9dea67fSPeter Grehan goto done; 359b9dea67fSPeter Grehan } 360b9dea67fSPeter Grehan r = 0; 361b9dea67fSPeter Grehan done: 3621dfdc15bSRoman Divacky if (cache != NULL) 3631dfdc15bSRoman Divacky free(cache); 3644b51c699SNathan Whitehorn 365f846c80aSKonstantin Belousov /* 366f846c80aSKonstantin Belousov * Synchronize icache for executable segments in case we made 367f846c80aSKonstantin Belousov * any changes. 368f846c80aSKonstantin Belousov */ 369f846c80aSKonstantin Belousov for (phdr = obj->phdr; 370f846c80aSKonstantin Belousov (const char *)phdr < (const char *)obj->phdr + obj->phsize; 371f846c80aSKonstantin Belousov phdr++) { 372f846c80aSKonstantin Belousov if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) { 373f846c80aSKonstantin Belousov __syncicache(obj->relocbase + phdr->p_vaddr, 374f846c80aSKonstantin Belousov phdr->p_memsz); 375f846c80aSKonstantin Belousov } 376f846c80aSKonstantin Belousov } 3774b51c699SNathan Whitehorn 378b9dea67fSPeter Grehan return (r); 379b9dea67fSPeter Grehan } 380b9dea67fSPeter Grehan 381b9dea67fSPeter Grehan /* 382b9dea67fSPeter Grehan * Initialise a PLT slot to the resolving trampoline 383b9dea67fSPeter Grehan */ 384b9dea67fSPeter Grehan static int 385b9dea67fSPeter Grehan reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 386b9dea67fSPeter Grehan { 387b9dea67fSPeter Grehan Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 3884f2730f7SNathan Whitehorn Elf_Addr *pltresolve, *pltlongresolve, *jmptab; 389b9dea67fSPeter Grehan Elf_Addr distance; 3904f2730f7SNathan Whitehorn int N = obj->pltrelasize / sizeof(Elf_Rela); 391b9dea67fSPeter Grehan int reloff; 392b9dea67fSPeter Grehan 393b9dea67fSPeter Grehan reloff = rela - obj->pltrela; 394b9dea67fSPeter Grehan 3954f2730f7SNathan Whitehorn if (reloff < 0) 396b9dea67fSPeter Grehan return (-1); 397b9dea67fSPeter Grehan 398f62da49bSJustin Hibbits if (obj->gotptr != NULL) { 399f62da49bSJustin Hibbits *where += (Elf_Addr)obj->relocbase; 400f62da49bSJustin Hibbits return (0); 401f62da49bSJustin Hibbits } 402f62da49bSJustin Hibbits 4034f2730f7SNathan Whitehorn pltlongresolve = obj->pltgot + 5; 4044f2730f7SNathan Whitehorn pltresolve = pltlongresolve + 5; 405b9dea67fSPeter Grehan 406b9dea67fSPeter Grehan distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); 407b9dea67fSPeter Grehan 408b9dea67fSPeter Grehan dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x", 409b9dea67fSPeter Grehan (void *)where, (void *)pltresolve, reloff, distance); 410b9dea67fSPeter Grehan 4114f2730f7SNathan Whitehorn if (reloff < PLT_EXTENDED_BEGIN) { 412b9dea67fSPeter Grehan /* li r11,reloff */ 413b9dea67fSPeter Grehan /* b pltresolve */ 414b9dea67fSPeter Grehan where[0] = 0x39600000 | reloff; 415b9dea67fSPeter Grehan where[1] = 0x48000000 | (distance & 0x03fffffc); 4164f2730f7SNathan Whitehorn } else { 4174f2730f7SNathan Whitehorn jmptab = obj->pltgot + JMPTAB_BASE(N); 4184f2730f7SNathan Whitehorn jmptab[reloff] = (u_int)pltlongresolve; 4194f2730f7SNathan Whitehorn 4204f2730f7SNathan Whitehorn /* lis r11,jmptab[reloff]@ha */ 4214f2730f7SNathan Whitehorn /* lwzu r12,jmptab[reloff]@l(r11) */ 4224f2730f7SNathan Whitehorn /* mtctr r12 */ 4234f2730f7SNathan Whitehorn /* bctr */ 4244f2730f7SNathan Whitehorn where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]); 4254f2730f7SNathan Whitehorn where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]); 4264f2730f7SNathan Whitehorn where[2] = 0x7d8903a6; 4274f2730f7SNathan Whitehorn where[3] = 0x4e800420; 4284f2730f7SNathan Whitehorn } 4294f2730f7SNathan Whitehorn 430b9dea67fSPeter Grehan 431b9dea67fSPeter Grehan /* 43217bbcc52SNathan Whitehorn * The icache will be sync'd in reloc_plt, which is called 433b9dea67fSPeter Grehan * after all the slots have been updated 434b9dea67fSPeter Grehan */ 435b9dea67fSPeter Grehan 436b9dea67fSPeter Grehan return (0); 437b9dea67fSPeter Grehan } 438b9dea67fSPeter Grehan 439b9dea67fSPeter Grehan /* 440b9dea67fSPeter Grehan * Process the PLT relocations. 441b9dea67fSPeter Grehan */ 442b9dea67fSPeter Grehan int 4434849c3a5SMichal Meloun reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused) 444b9dea67fSPeter Grehan { 445b9dea67fSPeter Grehan const Elf_Rela *relalim; 446b9dea67fSPeter Grehan const Elf_Rela *rela; 44717bbcc52SNathan Whitehorn int N = obj->pltrelasize / sizeof(Elf_Rela); 448b9dea67fSPeter Grehan 449b9dea67fSPeter Grehan if (obj->pltrelasize != 0) { 450b9dea67fSPeter Grehan 451903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela + 452b9dea67fSPeter Grehan obj->pltrelasize); 453b9dea67fSPeter Grehan for (rela = obj->pltrela; rela < relalim; rela++) { 45457462f8fSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 45557462f8fSBrandon Bergren dbg("ABI violation - found IRELATIVE in the PLT."); 45657462f8fSBrandon Bergren obj->irelative = true; 45757462f8fSBrandon Bergren continue; 45857462f8fSBrandon Bergren } 45957462f8fSBrandon Bergren 46057462f8fSBrandon Bergren /* 46157462f8fSBrandon Bergren * PowerPC(64) .rela.plt is composed of an array of 46257462f8fSBrandon Bergren * R_PPC_JMP_SLOT relocations. Unlike other platforms, 46357462f8fSBrandon Bergren * this is the ONLY relocation type that is valid here. 46457462f8fSBrandon Bergren */ 465b9dea67fSPeter Grehan assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 466b9dea67fSPeter Grehan 467b9dea67fSPeter Grehan if (reloc_plt_object(obj, rela) < 0) { 468b9dea67fSPeter Grehan return (-1); 469b9dea67fSPeter Grehan } 470b9dea67fSPeter Grehan } 471b9dea67fSPeter Grehan } 472b9dea67fSPeter Grehan 47317bbcc52SNathan Whitehorn /* 47417bbcc52SNathan Whitehorn * Sync the icache for the byte range represented by the 47517bbcc52SNathan Whitehorn * trampoline routines and call slots. 47617bbcc52SNathan Whitehorn */ 477f62da49bSJustin Hibbits if (obj->pltgot != NULL && obj->gotptr == NULL) 47817bbcc52SNathan Whitehorn __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); 47917bbcc52SNathan Whitehorn 480b9dea67fSPeter Grehan return (0); 481b9dea67fSPeter Grehan } 482b9dea67fSPeter Grehan 483b9dea67fSPeter Grehan /* 484b9dea67fSPeter Grehan * LD_BIND_NOW was set - force relocation for all jump slots 485b9dea67fSPeter Grehan */ 486b9dea67fSPeter Grehan int 487082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 488b9dea67fSPeter Grehan { 489b9dea67fSPeter Grehan const Obj_Entry *defobj; 490b9dea67fSPeter Grehan const Elf_Rela *relalim; 491b9dea67fSPeter Grehan const Elf_Rela *rela; 492b9dea67fSPeter Grehan const Elf_Sym *def; 493b9dea67fSPeter Grehan Elf_Addr *where; 494b9dea67fSPeter Grehan Elf_Addr target; 495b9dea67fSPeter Grehan 496903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela + 497903e0ffdSAlex Richardson obj->pltrelasize); 498b9dea67fSPeter Grehan for (rela = obj->pltrela; rela < relalim; rela++) { 49957462f8fSBrandon Bergren /* This isn't actually a jump slot, ignore it. */ 50057462f8fSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) 50157462f8fSBrandon Bergren continue; 502b9dea67fSPeter Grehan assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 503b9dea67fSPeter Grehan where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 504b9dea67fSPeter Grehan def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 505082f959aSKonstantin Belousov SYMLOOK_IN_PLT | flags, NULL, lockstate); 506b9dea67fSPeter Grehan if (def == NULL) { 507b9dea67fSPeter Grehan dbg("reloc_jmpslots: sym not found"); 508b9dea67fSPeter Grehan return (-1); 509b9dea67fSPeter Grehan } 510b9dea67fSPeter Grehan 511b9dea67fSPeter Grehan target = (Elf_Addr)(defobj->relocbase + def->st_value); 512b9dea67fSPeter Grehan 51357462f8fSBrandon Bergren if (def == &sym_zero) { 51457462f8fSBrandon Bergren /* Zero undefined weak symbols */ 51557462f8fSBrandon Bergren *where = 0; 51657462f8fSBrandon Bergren } else { 51757462f8fSBrandon Bergren if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 51857462f8fSBrandon Bergren /* LD_BIND_NOW, ifunc in shared lib.*/ 51957462f8fSBrandon Bergren obj->gnu_ifunc = true; 52057462f8fSBrandon Bergren continue; 52157462f8fSBrandon Bergren } 522b9dea67fSPeter Grehan reloc_jmpslot(where, target, defobj, obj, 523b9dea67fSPeter Grehan (const Elf_Rel *) rela); 524b9dea67fSPeter Grehan } 52557462f8fSBrandon Bergren } 526b9dea67fSPeter Grehan 527b9dea67fSPeter Grehan obj->jmpslots_done = true; 528b9dea67fSPeter Grehan 529b9dea67fSPeter Grehan return (0); 530b9dea67fSPeter Grehan } 531b9dea67fSPeter Grehan 532b9dea67fSPeter Grehan 533b9dea67fSPeter Grehan /* 53457462f8fSBrandon Bergren * Update the value of a PLT jump slot. 535b9dea67fSPeter Grehan */ 536b9dea67fSPeter Grehan Elf_Addr 537903e0ffdSAlex Richardson reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, 538903e0ffdSAlex Richardson const Obj_Entry *defobj __unused, const Obj_Entry *obj, const Elf_Rel *rel) 539b9dea67fSPeter Grehan { 540b9dea67fSPeter Grehan Elf_Addr offset; 541b9dea67fSPeter Grehan const Elf_Rela *rela = (const Elf_Rela *) rel; 542b9dea67fSPeter Grehan 543b9dea67fSPeter Grehan dbg(" reloc_jmpslot: where=%p, target=%p", 544b9dea67fSPeter Grehan (void *)wherep, (void *)target); 545b9dea67fSPeter Grehan 546e35ddbe4SKonstantin Belousov if (ld_bind_not) 547e35ddbe4SKonstantin Belousov goto out; 548e35ddbe4SKonstantin Belousov 54957462f8fSBrandon Bergren 55057462f8fSBrandon Bergren /* 55157462f8fSBrandon Bergren * Process Secure-PLT. 55257462f8fSBrandon Bergren */ 55357462f8fSBrandon Bergren if (obj->gotptr != NULL) { 55457462f8fSBrandon Bergren assert(wherep >= (Elf_Word *)obj->pltgot); 55557462f8fSBrandon Bergren assert(wherep < 55657462f8fSBrandon Bergren (Elf_Word *)obj->pltgot + obj->pltrelasize); 55757462f8fSBrandon Bergren if (*wherep != target) 55857462f8fSBrandon Bergren *wherep = target; 55957462f8fSBrandon Bergren goto out; 56057462f8fSBrandon Bergren } 56157462f8fSBrandon Bergren 56257462f8fSBrandon Bergren /* 56357462f8fSBrandon Bergren * BSS-PLT optimization: 56457462f8fSBrandon Bergren * Branch directly to the target if it is within +/- 32Mb, 56557462f8fSBrandon Bergren * otherwise go indirectly via the pltcall trampoline call and 56657462f8fSBrandon Bergren * jump table. 56757462f8fSBrandon Bergren */ 56857462f8fSBrandon Bergren offset = target - (Elf_Addr)wherep; 56957462f8fSBrandon Bergren if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */ 570b9dea67fSPeter Grehan /* 571b9dea67fSPeter Grehan * At the PLT entry pointed at by `wherep', construct 572b9dea67fSPeter Grehan * a direct transfer to the now fully resolved function 573b9dea67fSPeter Grehan * address. 574b9dea67fSPeter Grehan */ 575b9dea67fSPeter Grehan /* b value # branch directly */ 576b9dea67fSPeter Grehan *wherep = 0x48000000 | (offset & 0x03fffffc); 577b9dea67fSPeter Grehan __syncicache(wherep, 4); 578b9dea67fSPeter Grehan } else { 579b9dea67fSPeter Grehan Elf_Addr *pltcall, *jmptab; 580b9dea67fSPeter Grehan int distance; 581b9dea67fSPeter Grehan int N = obj->pltrelasize / sizeof(Elf_Rela); 582b9dea67fSPeter Grehan int reloff = rela - obj->pltrela; 583b9dea67fSPeter Grehan 5844f2730f7SNathan Whitehorn if (reloff < 0) 585b9dea67fSPeter Grehan return (-1); 586b9dea67fSPeter Grehan 587b9dea67fSPeter Grehan pltcall = obj->pltgot; 588b9dea67fSPeter Grehan 5894f2730f7SNathan Whitehorn dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n", 590b9dea67fSPeter Grehan reloff, N); 591b9dea67fSPeter Grehan 5924f2730f7SNathan Whitehorn jmptab = obj->pltgot + JMPTAB_BASE(N); 593b9dea67fSPeter Grehan jmptab[reloff] = target; 594c606eab4SNathan Whitehorn mb(); /* Order jmptab update before next changes */ 595b9dea67fSPeter Grehan 5964f2730f7SNathan Whitehorn if (reloff < PLT_EXTENDED_BEGIN) { 5974f2730f7SNathan Whitehorn /* for extended PLT entries, we keep the old code */ 5984f2730f7SNathan Whitehorn 599b9dea67fSPeter Grehan distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1); 600b9dea67fSPeter Grehan 601b9dea67fSPeter Grehan /* li r11,reloff */ 602b9dea67fSPeter Grehan /* b pltcall # use indirect pltcall routine */ 6039d00444dSNathan Whitehorn 6049d00444dSNathan Whitehorn /* first instruction same as before */ 605b9dea67fSPeter Grehan wherep[1] = 0x48000000 | (distance & 0x03fffffc); 606b9dea67fSPeter Grehan __syncicache(wherep, 8); 607b9dea67fSPeter Grehan } 6084f2730f7SNathan Whitehorn } 609b9dea67fSPeter Grehan 610e35ddbe4SKonstantin Belousov out: 611b9dea67fSPeter Grehan return (target); 612b9dea67fSPeter Grehan } 613b9dea67fSPeter Grehan 6146be4b697SKonstantin Belousov int 61557462f8fSBrandon Bergren reloc_iresolve(Obj_Entry *obj, 61657462f8fSBrandon Bergren struct Struct_RtldLockState *lockstate) 6176be4b697SKonstantin Belousov { 61857462f8fSBrandon Bergren /* 61957462f8fSBrandon Bergren * Since PLT slots on PowerPC are always R_PPC_JMP_SLOT, 62057462f8fSBrandon Bergren * R_PPC_IRELATIVE is in RELA. 62157462f8fSBrandon Bergren */ 62257462f8fSBrandon Bergren const Elf_Rela *relalim; 62357462f8fSBrandon Bergren const Elf_Rela *rela; 62457462f8fSBrandon Bergren Elf_Addr *where, target, *ptr; 6256be4b697SKonstantin Belousov 62657462f8fSBrandon Bergren if (!obj->irelative) 62757462f8fSBrandon Bergren return (0); 62857462f8fSBrandon Bergren 62957462f8fSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 63057462f8fSBrandon Bergren for (rela = obj->rela; rela < relalim; rela++) { 63157462f8fSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 63257462f8fSBrandon Bergren ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 63357462f8fSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 63457462f8fSBrandon Bergren 63557462f8fSBrandon Bergren lock_release(rtld_bind_lock, lockstate); 63657462f8fSBrandon Bergren target = call_ifunc_resolver(ptr); 63757462f8fSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate); 63857462f8fSBrandon Bergren 63957462f8fSBrandon Bergren *where = target; 64057462f8fSBrandon Bergren } 64157462f8fSBrandon Bergren } 64257462f8fSBrandon Bergren /* 64357462f8fSBrandon Bergren * XXX Remove me when lld is fixed! 64457462f8fSBrandon Bergren * LLD currently makes illegal relocations in the PLT. 64557462f8fSBrandon Bergren */ 64657462f8fSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 64757462f8fSBrandon Bergren for (rela = obj->pltrela; rela < relalim; rela++) { 64857462f8fSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 64957462f8fSBrandon Bergren ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 65057462f8fSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 65157462f8fSBrandon Bergren 65257462f8fSBrandon Bergren lock_release(rtld_bind_lock, lockstate); 65357462f8fSBrandon Bergren target = call_ifunc_resolver(ptr); 65457462f8fSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate); 65557462f8fSBrandon Bergren 65657462f8fSBrandon Bergren *where = target; 65757462f8fSBrandon Bergren } 65857462f8fSBrandon Bergren } 65957462f8fSBrandon Bergren 66057462f8fSBrandon Bergren obj->irelative = false; 6616be4b697SKonstantin Belousov return (0); 6626be4b697SKonstantin Belousov } 6636be4b697SKonstantin Belousov 6646be4b697SKonstantin Belousov int 665c5ca0d11SKonstantin Belousov reloc_iresolve_nonplt(Obj_Entry *obj __unused, 666c5ca0d11SKonstantin Belousov struct Struct_RtldLockState *lockstate __unused) 667c5ca0d11SKonstantin Belousov { 668c5ca0d11SKonstantin Belousov return (0); 669c5ca0d11SKonstantin Belousov } 670c5ca0d11SKonstantin Belousov 671c5ca0d11SKonstantin Belousov int 672903e0ffdSAlex Richardson reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused, 673903e0ffdSAlex Richardson struct Struct_RtldLockState *lockstate __unused) 6746be4b697SKonstantin Belousov { 67557462f8fSBrandon Bergren const Elf_Rela *relalim; 67657462f8fSBrandon Bergren const Elf_Rela *rela; 67757462f8fSBrandon Bergren Elf_Addr *where, target; 67857462f8fSBrandon Bergren const Elf_Sym *def; 67957462f8fSBrandon Bergren const Obj_Entry *defobj; 6806be4b697SKonstantin Belousov 68157462f8fSBrandon Bergren if (!obj->gnu_ifunc) 68257462f8fSBrandon Bergren return (0); 68357462f8fSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 68457462f8fSBrandon Bergren for (rela = obj->pltrela; rela < relalim; rela++) { 68557462f8fSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) { 68657462f8fSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 68757462f8fSBrandon Bergren def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 68857462f8fSBrandon Bergren SYMLOOK_IN_PLT | flags, NULL, lockstate); 68957462f8fSBrandon Bergren if (def == NULL) 69057462f8fSBrandon Bergren return (-1); 69157462f8fSBrandon Bergren if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 69257462f8fSBrandon Bergren continue; 69357462f8fSBrandon Bergren lock_release(rtld_bind_lock, lockstate); 69457462f8fSBrandon Bergren target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 69557462f8fSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate); 69657462f8fSBrandon Bergren reloc_jmpslot(where, target, defobj, obj, 69757462f8fSBrandon Bergren (const Elf_Rel *)rela); 69857462f8fSBrandon Bergren } 69957462f8fSBrandon Bergren } 70057462f8fSBrandon Bergren obj->gnu_ifunc = false; 7016be4b697SKonstantin Belousov return (0); 7026be4b697SKonstantin Belousov } 703b9dea67fSPeter Grehan 704b9dea67fSPeter Grehan /* 705b9dea67fSPeter Grehan * Setup the plt glue routines. 706b9dea67fSPeter Grehan */ 707b9dea67fSPeter Grehan #define PLTCALL_SIZE 20 7084f2730f7SNathan Whitehorn #define PLTLONGRESOLVE_SIZE 20 709b9dea67fSPeter Grehan #define PLTRESOLVE_SIZE 24 710b9dea67fSPeter Grehan 711b9dea67fSPeter Grehan void 712b9dea67fSPeter Grehan init_pltgot(Obj_Entry *obj) 713b9dea67fSPeter Grehan { 7144f2730f7SNathan Whitehorn Elf_Word *pltcall, *pltresolve, *pltlongresolve; 715b9dea67fSPeter Grehan Elf_Word *jmptab; 716b9dea67fSPeter Grehan int N = obj->pltrelasize / sizeof(Elf_Rela); 717b9dea67fSPeter Grehan 718b9dea67fSPeter Grehan pltcall = obj->pltgot; 719b9dea67fSPeter Grehan 720b9dea67fSPeter Grehan if (pltcall == NULL) { 721b9dea67fSPeter Grehan return; 722b9dea67fSPeter Grehan } 723b9dea67fSPeter Grehan 724f62da49bSJustin Hibbits /* Handle Secure-PLT first, if applicable. */ 725f62da49bSJustin Hibbits if (obj->gotptr != NULL) { 726f62da49bSJustin Hibbits obj->gotptr[1] = (Elf_Addr)_rtld_bind_secureplt_start; 727f62da49bSJustin Hibbits obj->gotptr[2] = (Elf_Addr)obj; 728f62da49bSJustin Hibbits dbg("obj %s secure-plt gotptr=%p start=%p obj=%p", 729f62da49bSJustin Hibbits obj->path, obj->gotptr, 730f62da49bSJustin Hibbits (void *)obj->gotptr[1], (void *)obj->gotptr[2]); 731f62da49bSJustin Hibbits return; 732f62da49bSJustin Hibbits } 733f62da49bSJustin Hibbits 734b9dea67fSPeter Grehan /* 735b9dea67fSPeter Grehan * From the SVR4 PPC ABI: 736b9dea67fSPeter Grehan * 737b9dea67fSPeter Grehan * 'The first 18 words (72 bytes) of the PLT are reserved for 738b9dea67fSPeter Grehan * use by the dynamic linker. 739b9dea67fSPeter Grehan * ... 740b9dea67fSPeter Grehan * 'If the executable or shared object requires N procedure 741b9dea67fSPeter Grehan * linkage table entries, the link editor shall reserve 3*N 742b9dea67fSPeter Grehan * words (12*N bytes) following the 18 reserved words. The 743b9dea67fSPeter Grehan * first 2*N of these words are the procedure linkage table 744b9dea67fSPeter Grehan * entries themselves. The static linker directs calls to bytes 745b9dea67fSPeter Grehan * (72 + (i-1)*8), for i between 1 and N inclusive. The remaining 746b9dea67fSPeter Grehan * N words (4*N bytes) are reserved for use by the dynamic linker.' 747b9dea67fSPeter Grehan */ 748b9dea67fSPeter Grehan 749b9dea67fSPeter Grehan /* 750b9dea67fSPeter Grehan * Copy the absolute-call assembler stub into the first part of 751b9dea67fSPeter Grehan * the reserved PLT area. 752b9dea67fSPeter Grehan */ 753b9dea67fSPeter Grehan memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); 754b9dea67fSPeter Grehan 755b9dea67fSPeter Grehan /* 756b9dea67fSPeter Grehan * Determine the address of the jumptable, which is the dyn-linker 757b9dea67fSPeter Grehan * reserved area after the call cells. Write the absolute address 758b9dea67fSPeter Grehan * of the jumptable into the absolute-call assembler code so it 759b9dea67fSPeter Grehan * can determine this address. 760b9dea67fSPeter Grehan */ 7614f2730f7SNathan Whitehorn jmptab = obj->pltgot + JMPTAB_BASE(N); 762b9dea67fSPeter Grehan pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */ 763b9dea67fSPeter Grehan pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */ 764b9dea67fSPeter Grehan 765b9dea67fSPeter Grehan /* 7664f2730f7SNathan Whitehorn * Skip down 20 bytes into the initial reserved area and copy 767b9dea67fSPeter Grehan * in the standard resolving assembler call. Into this assembler, 768b9dea67fSPeter Grehan * insert the absolute address of the _rtld_bind_start routine 769b9dea67fSPeter Grehan * and the address of the relocation object. 7704f2730f7SNathan Whitehorn * 7714f2730f7SNathan Whitehorn * We place pltlongresolve first, so it can fix up its arguments 7724f2730f7SNathan Whitehorn * and then fall through to the regular PLT resolver. 773b9dea67fSPeter Grehan */ 7744f2730f7SNathan Whitehorn pltlongresolve = obj->pltgot + 5; 775b9dea67fSPeter Grehan 7764f2730f7SNathan Whitehorn memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve, 7774f2730f7SNathan Whitehorn PLTLONGRESOLVE_SIZE); 7784f2730f7SNathan Whitehorn pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */ 7794f2730f7SNathan Whitehorn pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */ 7804f2730f7SNathan Whitehorn 7814f2730f7SNathan Whitehorn pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t); 782b9dea67fSPeter Grehan memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); 783b9dea67fSPeter Grehan pltresolve[0] |= _ppc_ha(_rtld_bind_start); 784b9dea67fSPeter Grehan pltresolve[1] |= _ppc_la(_rtld_bind_start); 785b9dea67fSPeter Grehan pltresolve[3] |= _ppc_ha(obj); 786b9dea67fSPeter Grehan pltresolve[4] |= _ppc_la(obj); 787b9dea67fSPeter Grehan 788b9dea67fSPeter Grehan /* 78917bbcc52SNathan Whitehorn * The icache will be sync'd in reloc_plt, which is called 79017bbcc52SNathan Whitehorn * after all the slots have been updated 791b9dea67fSPeter Grehan */ 792b9dea67fSPeter Grehan } 793fca32c74SDoug Rabson 79457462f8fSBrandon Bergren /* 79557462f8fSBrandon Bergren * 32 bit cpu feature flag fields. 79657462f8fSBrandon Bergren */ 79757462f8fSBrandon Bergren u_long cpu_features; 79857462f8fSBrandon Bergren u_long cpu_features2; 79957462f8fSBrandon Bergren 80057462f8fSBrandon Bergren void 80157462f8fSBrandon Bergren powerpc_abi_variant_hook(Elf_Auxinfo** aux_info) 80257462f8fSBrandon Bergren { 80357462f8fSBrandon Bergren /* 80457462f8fSBrandon Bergren * Since aux_info[] is easier to work with than aux, go ahead and 80557462f8fSBrandon Bergren * initialize cpu_features / cpu_features2. 80657462f8fSBrandon Bergren */ 80757462f8fSBrandon Bergren cpu_features = -1UL; 80857462f8fSBrandon Bergren cpu_features2 = -1UL; 80957462f8fSBrandon Bergren if (aux_info[AT_HWCAP] != NULL) 81057462f8fSBrandon Bergren cpu_features = aux_info[AT_HWCAP]->a_un.a_val; 81157462f8fSBrandon Bergren if (aux_info[AT_HWCAP2] != NULL) 81257462f8fSBrandon Bergren cpu_features2 = aux_info[AT_HWCAP2]->a_un.a_val; 81357462f8fSBrandon Bergren } 81457462f8fSBrandon Bergren 815fca32c74SDoug Rabson void 816d27078f9SKonstantin Belousov ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 8174352999eSKonstantin Belousov { 81841fc6f68SMarius Strobl 81941fc6f68SMarius Strobl } 82041fc6f68SMarius Strobl 82141fc6f68SMarius Strobl void 822fca32c74SDoug Rabson allocate_initial_tls(Obj_Entry *list) 823fca32c74SDoug Rabson { 824fca32c74SDoug Rabson 825fca32c74SDoug Rabson /* 826fca32c74SDoug Rabson * Fix the size of the static TLS block by using the maximum 827fca32c74SDoug Rabson * offset allocated so far and adding a bit for dynamic modules to 828fca32c74SDoug Rabson * use. 829fca32c74SDoug Rabson */ 830fca32c74SDoug Rabson 83195335dd3SStephen J. Kiernan tls_static_space = tls_last_offset + tls_last_size + 83295335dd3SStephen J. Kiernan ld_static_tls_extra; 833fca32c74SDoug Rabson 8348bcdb144SJohn Baldwin _tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); 835fca32c74SDoug Rabson } 836fca32c74SDoug Rabson 837fca32c74SDoug Rabson void* 838fca32c74SDoug Rabson __tls_get_addr(tls_index* ti) 839fca32c74SDoug Rabson { 8408bcdb144SJohn Baldwin uintptr_t **dtvp; 841fca32c74SDoug Rabson char *p; 842fca32c74SDoug Rabson 8438bcdb144SJohn Baldwin dtvp = &_tcb_get()->tcb_dtv; 8448bcdb144SJohn Baldwin p = tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset); 8456c2a9753SSuleiman Souhlal 8466c2a9753SSuleiman Souhlal return (p + TLS_DTV_OFFSET); 847fca32c74SDoug Rabson } 848