1b9dea67fSPeter Grehan /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 2b9dea67fSPeter Grehan 3b9dea67fSPeter Grehan /*- 4b9dea67fSPeter Grehan * Copyright (C) 1998 Tsubai Masanari 5b9dea67fSPeter Grehan * All rights reserved. 6b9dea67fSPeter Grehan * 7b9dea67fSPeter Grehan * Redistribution and use in source and binary forms, with or without 8b9dea67fSPeter Grehan * modification, are permitted provided that the following conditions 9b9dea67fSPeter Grehan * are met: 10b9dea67fSPeter Grehan * 1. Redistributions of source code must retain the above copyright 11b9dea67fSPeter Grehan * notice, this list of conditions and the following disclaimer. 12b9dea67fSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 13b9dea67fSPeter Grehan * notice, this list of conditions and the following disclaimer in the 14b9dea67fSPeter Grehan * documentation and/or other materials provided with the distribution. 15b9dea67fSPeter Grehan * 3. The name of the author may not be used to endorse or promote products 16b9dea67fSPeter Grehan * derived from this software without specific prior written permission. 17b9dea67fSPeter Grehan * 18b9dea67fSPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19b9dea67fSPeter Grehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20b9dea67fSPeter Grehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21b9dea67fSPeter Grehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22b9dea67fSPeter Grehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23b9dea67fSPeter Grehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24b9dea67fSPeter Grehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25b9dea67fSPeter Grehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26b9dea67fSPeter Grehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27b9dea67fSPeter Grehan * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28b9dea67fSPeter Grehan * 29b9dea67fSPeter Grehan * $FreeBSD$ 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> 40b9dea67fSPeter Grehan #include <machine/cpu.h> 41b9dea67fSPeter Grehan 42b9dea67fSPeter Grehan #include "debug.h" 43b9dea67fSPeter Grehan #include "rtld.h" 44b9dea67fSPeter Grehan 45b9dea67fSPeter Grehan #define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \ 46b9dea67fSPeter Grehan ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) 47b9dea67fSPeter Grehan #define _ppc_la(x) ((u_int32_t)(x) & 0xffff) 48b9dea67fSPeter Grehan 49b9dea67fSPeter Grehan /* 50b9dea67fSPeter Grehan * Process the R_PPC_COPY relocations 51b9dea67fSPeter Grehan */ 52b9dea67fSPeter Grehan int 53b9dea67fSPeter Grehan do_copy_relocations(Obj_Entry *dstobj) 54b9dea67fSPeter Grehan { 55b9dea67fSPeter Grehan const Elf_Rela *relalim; 56b9dea67fSPeter Grehan const Elf_Rela *rela; 57b9dea67fSPeter Grehan 58b9dea67fSPeter Grehan /* 59b9dea67fSPeter Grehan * COPY relocs are invalid outside of the main program 60b9dea67fSPeter Grehan */ 61b9dea67fSPeter Grehan assert(dstobj->mainprog); 62b9dea67fSPeter Grehan 63b9dea67fSPeter Grehan relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + 64b9dea67fSPeter Grehan dstobj->relasize); 65b9dea67fSPeter Grehan for (rela = dstobj->rela; rela < relalim; rela++) { 66b9dea67fSPeter Grehan void *dstaddr; 67b9dea67fSPeter Grehan const Elf_Sym *dstsym; 68b9dea67fSPeter Grehan const char *name; 69b9dea67fSPeter Grehan unsigned long hash; 70b9dea67fSPeter Grehan size_t size; 71b9dea67fSPeter Grehan const void *srcaddr; 72b9dea67fSPeter Grehan const Elf_Sym *srcsym = NULL; 73b9dea67fSPeter Grehan Obj_Entry *srcobj; 74b9dea67fSPeter Grehan 75b9dea67fSPeter Grehan if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 76b9dea67fSPeter Grehan continue; 77b9dea67fSPeter Grehan } 78b9dea67fSPeter Grehan 79b9dea67fSPeter Grehan dstaddr = (void *) (dstobj->relocbase + rela->r_offset); 80b9dea67fSPeter Grehan dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 81b9dea67fSPeter Grehan name = dstobj->strtab + dstsym->st_name; 82b9dea67fSPeter Grehan hash = elf_hash(name); 83b9dea67fSPeter Grehan size = dstsym->st_size; 84b9dea67fSPeter Grehan 85b9dea67fSPeter Grehan for (srcobj = dstobj->next; srcobj != NULL; 86b9dea67fSPeter Grehan srcobj = srcobj->next) { 87b9dea67fSPeter Grehan if ((srcsym = symlook_obj(name, hash, srcobj, false)) 88b9dea67fSPeter Grehan != NULL) { 89b9dea67fSPeter Grehan break; 90b9dea67fSPeter Grehan } 91b9dea67fSPeter Grehan } 92b9dea67fSPeter Grehan 93b9dea67fSPeter Grehan if (srcobj == NULL) { 94b9dea67fSPeter Grehan _rtld_error("Undefined symbol \"%s\" " 95b9dea67fSPeter Grehan " referenced from COPY" 96b9dea67fSPeter Grehan " relocation in %s", name, dstobj->path); 97b9dea67fSPeter Grehan return (-1); 98b9dea67fSPeter Grehan } 99b9dea67fSPeter Grehan 100b9dea67fSPeter Grehan srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value); 101b9dea67fSPeter Grehan memcpy(dstaddr, srcaddr, size); 102b9dea67fSPeter Grehan dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size); 103b9dea67fSPeter Grehan } 104b9dea67fSPeter Grehan 105b9dea67fSPeter Grehan return (0); 106b9dea67fSPeter Grehan } 107b9dea67fSPeter Grehan 108b9dea67fSPeter Grehan 109b9dea67fSPeter Grehan /* 110b9dea67fSPeter Grehan * Perform early relocation of the run-time linker image 111b9dea67fSPeter Grehan */ 112b9dea67fSPeter Grehan void 113b9dea67fSPeter Grehan reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 114b9dea67fSPeter Grehan { 115b9dea67fSPeter Grehan const Elf_Rela *rela = 0, *relalim; 116b9dea67fSPeter Grehan Elf_Addr relasz = 0; 117b9dea67fSPeter Grehan Elf_Addr *where; 118b9dea67fSPeter Grehan 119b9dea67fSPeter Grehan /* 120b9dea67fSPeter Grehan * Extract the rela/relasz values from the dynamic section 121b9dea67fSPeter Grehan */ 122b9dea67fSPeter Grehan for (; dynp->d_tag != DT_NULL; dynp++) { 123b9dea67fSPeter Grehan switch (dynp->d_tag) { 124b9dea67fSPeter Grehan case DT_RELA: 125b9dea67fSPeter Grehan rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 126b9dea67fSPeter Grehan break; 127b9dea67fSPeter Grehan case DT_RELASZ: 128b9dea67fSPeter Grehan relasz = dynp->d_un.d_val; 129b9dea67fSPeter Grehan break; 130b9dea67fSPeter Grehan } 131b9dea67fSPeter Grehan } 132b9dea67fSPeter Grehan 133b9dea67fSPeter Grehan /* 134b9dea67fSPeter Grehan * Relocate these values 135b9dea67fSPeter Grehan */ 136b9dea67fSPeter Grehan relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 137b9dea67fSPeter Grehan for (; rela < relalim; rela++) { 138b9dea67fSPeter Grehan where = (Elf_Addr *)(relocbase + rela->r_offset); 139b9dea67fSPeter Grehan *where = (Elf_Addr)(relocbase + rela->r_addend); 140b9dea67fSPeter Grehan } 141b9dea67fSPeter Grehan } 142b9dea67fSPeter Grehan 143b9dea67fSPeter Grehan 144b9dea67fSPeter Grehan /* 145b9dea67fSPeter Grehan * Relocate a non-PLT object with addend. 146b9dea67fSPeter Grehan */ 147b9dea67fSPeter Grehan static int 148b9dea67fSPeter Grehan reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 149b9dea67fSPeter Grehan SymCache *cache) 150b9dea67fSPeter Grehan { 151b9dea67fSPeter Grehan Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 152b9dea67fSPeter Grehan const Elf_Sym *def; 153b9dea67fSPeter Grehan const Obj_Entry *defobj; 154b9dea67fSPeter Grehan Elf_Addr tmp; 155b9dea67fSPeter Grehan 156b9dea67fSPeter Grehan switch (ELF_R_TYPE(rela->r_info)) { 157b9dea67fSPeter Grehan 158b9dea67fSPeter Grehan case R_PPC_NONE: 159b9dea67fSPeter Grehan break; 160b9dea67fSPeter Grehan 161b9dea67fSPeter Grehan case R_PPC_ADDR32: /* word32 S + A */ 162b9dea67fSPeter Grehan case R_PPC_GLOB_DAT: /* word32 S + A */ 163b9dea67fSPeter Grehan def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 164b9dea67fSPeter Grehan false, cache); 165b9dea67fSPeter Grehan if (def == NULL) { 166b9dea67fSPeter Grehan return (-1); 167b9dea67fSPeter Grehan } 168b9dea67fSPeter Grehan 169b9dea67fSPeter Grehan tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 170b9dea67fSPeter Grehan rela->r_addend); 171b9dea67fSPeter Grehan 172b9dea67fSPeter Grehan /* Don't issue write if unnecessary; avoid COW page fault */ 173b9dea67fSPeter Grehan if (*where != tmp) { 174b9dea67fSPeter Grehan *where = tmp; 175b9dea67fSPeter Grehan } 176b9dea67fSPeter Grehan break; 177b9dea67fSPeter Grehan 178b9dea67fSPeter Grehan case R_PPC_RELATIVE: /* word32 B + A */ 179b9dea67fSPeter Grehan tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 180b9dea67fSPeter Grehan 181b9dea67fSPeter Grehan /* As above, don't issue write unnecessarily */ 182b9dea67fSPeter Grehan if (*where != tmp) { 183b9dea67fSPeter Grehan *where = tmp; 184b9dea67fSPeter Grehan } 185b9dea67fSPeter Grehan break; 186b9dea67fSPeter Grehan 187b9dea67fSPeter Grehan case R_PPC_COPY: 188b9dea67fSPeter Grehan /* 189b9dea67fSPeter Grehan * These are deferred until all other relocations 190b9dea67fSPeter Grehan * have been done. All we do here is make sure 191b9dea67fSPeter Grehan * that the COPY relocation is not in a shared 192b9dea67fSPeter Grehan * library. They are allowed only in executable 193b9dea67fSPeter Grehan * files. 194b9dea67fSPeter Grehan */ 195b9dea67fSPeter Grehan if (!obj->mainprog) { 196b9dea67fSPeter Grehan _rtld_error("%s: Unexpected R_COPY " 197b9dea67fSPeter Grehan " relocation in shared library", 198b9dea67fSPeter Grehan obj->path); 199b9dea67fSPeter Grehan return (-1); 200b9dea67fSPeter Grehan } 201b9dea67fSPeter Grehan break; 202b9dea67fSPeter Grehan 203b9dea67fSPeter Grehan case R_PPC_JMP_SLOT: 204b9dea67fSPeter Grehan /* 205b9dea67fSPeter Grehan * These will be handled by the plt/jmpslot routines 206b9dea67fSPeter Grehan */ 207b9dea67fSPeter Grehan break; 208b9dea67fSPeter Grehan 209b9dea67fSPeter Grehan default: 210b9dea67fSPeter Grehan _rtld_error("%s: Unsupported relocation type %d" 211b9dea67fSPeter Grehan " in non-PLT relocations\n", obj->path, 212b9dea67fSPeter Grehan ELF_R_TYPE(rela->r_info)); 213b9dea67fSPeter Grehan return (-1); 214b9dea67fSPeter Grehan } 215b9dea67fSPeter Grehan return (0); 216b9dea67fSPeter Grehan } 217b9dea67fSPeter Grehan 218b9dea67fSPeter Grehan 219b9dea67fSPeter Grehan /* 220b9dea67fSPeter Grehan * Process non-PLT relocations 221b9dea67fSPeter Grehan */ 222b9dea67fSPeter Grehan int 223b9dea67fSPeter Grehan reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) 224b9dea67fSPeter Grehan { 225b9dea67fSPeter Grehan const Elf_Rela *relalim; 226b9dea67fSPeter Grehan const Elf_Rela *rela; 227b9dea67fSPeter Grehan SymCache *cache; 228b9dea67fSPeter Grehan int bytes = obj->nchains * sizeof(SymCache); 229b9dea67fSPeter Grehan int r = -1; 230b9dea67fSPeter Grehan 231b9dea67fSPeter Grehan /* 232b9dea67fSPeter Grehan * The dynamic loader may be called from a thread, we have 233b9dea67fSPeter Grehan * limited amounts of stack available so we cannot use alloca(). 234b9dea67fSPeter Grehan */ 235b9dea67fSPeter Grehan cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 236b9dea67fSPeter Grehan if (cache == MAP_FAILED) { 237b9dea67fSPeter Grehan cache = NULL; 238b9dea67fSPeter Grehan } 239b9dea67fSPeter Grehan if (cache != NULL) { 240b9dea67fSPeter Grehan memset(cache, 0, obj->nchains * sizeof(SymCache)); 241b9dea67fSPeter Grehan } 242b9dea67fSPeter Grehan 243b9dea67fSPeter Grehan /* 244b9dea67fSPeter Grehan * From the SVR4 PPC ABI: 245b9dea67fSPeter Grehan * "The PowerPC family uses only the Elf32_Rela relocation 246b9dea67fSPeter Grehan * entries with explicit addends." 247b9dea67fSPeter Grehan */ 248b9dea67fSPeter Grehan relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 249b9dea67fSPeter Grehan for (rela = obj->rela; rela < relalim; rela++) { 250b9dea67fSPeter Grehan if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0) 251b9dea67fSPeter Grehan goto done; 252b9dea67fSPeter Grehan } 253b9dea67fSPeter Grehan r = 0; 254b9dea67fSPeter Grehan done: 255b9dea67fSPeter Grehan if (cache) { 256b9dea67fSPeter Grehan munmap(cache, bytes); 257b9dea67fSPeter Grehan } 258b9dea67fSPeter Grehan return (r); 259b9dea67fSPeter Grehan } 260b9dea67fSPeter Grehan 261b9dea67fSPeter Grehan 262b9dea67fSPeter Grehan /* 263b9dea67fSPeter Grehan * Initialise a PLT slot to the resolving trampoline 264b9dea67fSPeter Grehan */ 265b9dea67fSPeter Grehan static int 266b9dea67fSPeter Grehan reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 267b9dea67fSPeter Grehan { 268b9dea67fSPeter Grehan Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 269b9dea67fSPeter Grehan Elf_Addr *pltresolve; 270b9dea67fSPeter Grehan Elf_Addr distance; 271b9dea67fSPeter Grehan int reloff; 272b9dea67fSPeter Grehan 273b9dea67fSPeter Grehan reloff = rela - obj->pltrela; 274b9dea67fSPeter Grehan 275b9dea67fSPeter Grehan if ((reloff < 0) || (reloff >= 0x8000)) { 276b9dea67fSPeter Grehan return (-1); 277b9dea67fSPeter Grehan } 278b9dea67fSPeter Grehan 279b9dea67fSPeter Grehan pltresolve = obj->pltgot + 8; 280b9dea67fSPeter Grehan 281b9dea67fSPeter Grehan distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); 282b9dea67fSPeter Grehan 283b9dea67fSPeter Grehan dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x", 284b9dea67fSPeter Grehan (void *)where, (void *)pltresolve, reloff, distance); 285b9dea67fSPeter Grehan 286b9dea67fSPeter Grehan /* li r11,reloff */ 287b9dea67fSPeter Grehan /* b pltresolve */ 288b9dea67fSPeter Grehan where[0] = 0x39600000 | reloff; 289b9dea67fSPeter Grehan where[1] = 0x48000000 | (distance & 0x03fffffc); 290b9dea67fSPeter Grehan 291b9dea67fSPeter Grehan /* 292b9dea67fSPeter Grehan * The icache will be sync'd in init_pltgot, which is called 293b9dea67fSPeter Grehan * after all the slots have been updated 294b9dea67fSPeter Grehan */ 295b9dea67fSPeter Grehan 296b9dea67fSPeter Grehan return (0); 297b9dea67fSPeter Grehan } 298b9dea67fSPeter Grehan 299b9dea67fSPeter Grehan 300b9dea67fSPeter Grehan /* 301b9dea67fSPeter Grehan * Process the PLT relocations. 302b9dea67fSPeter Grehan */ 303b9dea67fSPeter Grehan int 304b9dea67fSPeter Grehan reloc_plt(Obj_Entry *obj) 305b9dea67fSPeter Grehan { 306b9dea67fSPeter Grehan const Elf_Rela *relalim; 307b9dea67fSPeter Grehan const Elf_Rela *rela; 308b9dea67fSPeter Grehan 309b9dea67fSPeter Grehan if (obj->pltrelasize != 0) { 310b9dea67fSPeter Grehan 311b9dea67fSPeter Grehan relalim = (const Elf_Rela *)((char *)obj->pltrela + 312b9dea67fSPeter Grehan obj->pltrelasize); 313b9dea67fSPeter Grehan for (rela = obj->pltrela; rela < relalim; rela++) { 314b9dea67fSPeter Grehan assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 315b9dea67fSPeter Grehan 316b9dea67fSPeter Grehan if (reloc_plt_object(obj, rela) < 0) { 317b9dea67fSPeter Grehan return (-1); 318b9dea67fSPeter Grehan } 319b9dea67fSPeter Grehan } 320b9dea67fSPeter Grehan } 321b9dea67fSPeter Grehan 322b9dea67fSPeter Grehan return (0); 323b9dea67fSPeter Grehan } 324b9dea67fSPeter Grehan 325b9dea67fSPeter Grehan 326b9dea67fSPeter Grehan /* 327b9dea67fSPeter Grehan * LD_BIND_NOW was set - force relocation for all jump slots 328b9dea67fSPeter Grehan */ 329b9dea67fSPeter Grehan int 330b9dea67fSPeter Grehan reloc_jmpslots(Obj_Entry *obj) 331b9dea67fSPeter Grehan { 332b9dea67fSPeter Grehan const Obj_Entry *defobj; 333b9dea67fSPeter Grehan const Elf_Rela *relalim; 334b9dea67fSPeter Grehan const Elf_Rela *rela; 335b9dea67fSPeter Grehan const Elf_Sym *def; 336b9dea67fSPeter Grehan Elf_Addr *where; 337b9dea67fSPeter Grehan Elf_Addr target; 338b9dea67fSPeter Grehan 339b9dea67fSPeter Grehan relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 340b9dea67fSPeter Grehan for (rela = obj->pltrela; rela < relalim; rela++) { 341b9dea67fSPeter Grehan assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 342b9dea67fSPeter Grehan where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 343b9dea67fSPeter Grehan def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 344b9dea67fSPeter Grehan true, NULL); 345b9dea67fSPeter Grehan if (def == NULL) { 346b9dea67fSPeter Grehan dbg("reloc_jmpslots: sym not found"); 347b9dea67fSPeter Grehan return (-1); 348b9dea67fSPeter Grehan } 349b9dea67fSPeter Grehan 350b9dea67fSPeter Grehan target = (Elf_Addr)(defobj->relocbase + def->st_value); 351b9dea67fSPeter Grehan 352b9dea67fSPeter Grehan #if 0 353b9dea67fSPeter Grehan /* PG XXX */ 354b9dea67fSPeter Grehan dbg("\"%s\" in \"%s\" --> %p in \"%s\"", 355b9dea67fSPeter Grehan defobj->strtab + def->st_name, basename(obj->path), 356b9dea67fSPeter Grehan (void *)target, basename(defobj->path)); 357b9dea67fSPeter Grehan #endif 358b9dea67fSPeter Grehan 359b9dea67fSPeter Grehan reloc_jmpslot(where, target, defobj, obj, 360b9dea67fSPeter Grehan (const Elf_Rel *) rela); 361b9dea67fSPeter Grehan } 362b9dea67fSPeter Grehan 363b9dea67fSPeter Grehan obj->jmpslots_done = true; 364b9dea67fSPeter Grehan 365b9dea67fSPeter Grehan return (0); 366b9dea67fSPeter Grehan } 367b9dea67fSPeter Grehan 368b9dea67fSPeter Grehan 369b9dea67fSPeter Grehan /* 370b9dea67fSPeter Grehan * Update the value of a PLT jump slot. Branch directly to the target if 371b9dea67fSPeter Grehan * it is within +/- 32Mb, otherwise go indirectly via the pltcall 372b9dea67fSPeter Grehan * trampoline call and jump table. 373b9dea67fSPeter Grehan */ 374b9dea67fSPeter Grehan Elf_Addr 375b9dea67fSPeter Grehan reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, 376b9dea67fSPeter Grehan const Obj_Entry *obj, const Elf_Rel *rel) 377b9dea67fSPeter Grehan { 378b9dea67fSPeter Grehan Elf_Addr offset; 379b9dea67fSPeter Grehan const Elf_Rela *rela = (const Elf_Rela *) rel; 380b9dea67fSPeter Grehan 381b9dea67fSPeter Grehan dbg(" reloc_jmpslot: where=%p, target=%p", 382b9dea67fSPeter Grehan (void *)wherep, (void *)target); 383b9dea67fSPeter Grehan 384b9dea67fSPeter Grehan /* 385b9dea67fSPeter Grehan * At the PLT entry pointed at by `wherep', construct 386b9dea67fSPeter Grehan * a direct transfer to the now fully resolved function 387b9dea67fSPeter Grehan * address. 388b9dea67fSPeter Grehan */ 389b9dea67fSPeter Grehan offset = target - (Elf_Addr)wherep; 390b9dea67fSPeter Grehan 391b9dea67fSPeter Grehan if (abs(offset) < 32*1024*1024) { /* inside 32MB? */ 392b9dea67fSPeter Grehan /* b value # branch directly */ 393b9dea67fSPeter Grehan *wherep = 0x48000000 | (offset & 0x03fffffc); 394b9dea67fSPeter Grehan __syncicache(wherep, 4); 395b9dea67fSPeter Grehan } else { 396b9dea67fSPeter Grehan Elf_Addr *pltcall, *jmptab; 397b9dea67fSPeter Grehan int distance; 398b9dea67fSPeter Grehan int N = obj->pltrelasize / sizeof(Elf_Rela); 399b9dea67fSPeter Grehan int reloff = rela - obj->pltrela; 400b9dea67fSPeter Grehan 401b9dea67fSPeter Grehan if ((reloff < 0) || (reloff >= 0x8000)) { 402b9dea67fSPeter Grehan return (-1); 403b9dea67fSPeter Grehan } 404b9dea67fSPeter Grehan 405b9dea67fSPeter Grehan pltcall = obj->pltgot; 406b9dea67fSPeter Grehan 407b9dea67fSPeter Grehan dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n", 408b9dea67fSPeter Grehan reloff, N); 409b9dea67fSPeter Grehan 410b9dea67fSPeter Grehan jmptab = obj->pltgot + 18 + N * 2; 411b9dea67fSPeter Grehan jmptab[reloff] = target; 412b9dea67fSPeter Grehan 413b9dea67fSPeter Grehan distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1); 414b9dea67fSPeter Grehan 415b9dea67fSPeter Grehan /* li r11,reloff */ 416b9dea67fSPeter Grehan /* b pltcall # use indirect pltcall routine */ 417b9dea67fSPeter Grehan wherep[0] = 0x39600000 | reloff; 418b9dea67fSPeter Grehan wherep[1] = 0x48000000 | (distance & 0x03fffffc); 419b9dea67fSPeter Grehan __syncicache(wherep, 8); 420b9dea67fSPeter Grehan } 421b9dea67fSPeter Grehan 422b9dea67fSPeter Grehan return (target); 423b9dea67fSPeter Grehan } 424b9dea67fSPeter Grehan 425b9dea67fSPeter Grehan 426b9dea67fSPeter Grehan /* 427b9dea67fSPeter Grehan * Setup the plt glue routines. 428b9dea67fSPeter Grehan */ 429b9dea67fSPeter Grehan #define PLTCALL_SIZE 20 430b9dea67fSPeter Grehan #define PLTRESOLVE_SIZE 24 431b9dea67fSPeter Grehan 432b9dea67fSPeter Grehan void 433b9dea67fSPeter Grehan init_pltgot(Obj_Entry *obj) 434b9dea67fSPeter Grehan { 435b9dea67fSPeter Grehan Elf_Word *pltcall, *pltresolve; 436b9dea67fSPeter Grehan Elf_Word *jmptab; 437b9dea67fSPeter Grehan int N = obj->pltrelasize / sizeof(Elf_Rela); 438b9dea67fSPeter Grehan 439b9dea67fSPeter Grehan pltcall = obj->pltgot; 440b9dea67fSPeter Grehan 441b9dea67fSPeter Grehan if (pltcall == NULL) { 442b9dea67fSPeter Grehan return; 443b9dea67fSPeter Grehan } 444b9dea67fSPeter Grehan 445b9dea67fSPeter Grehan /* 446b9dea67fSPeter Grehan * From the SVR4 PPC ABI: 447b9dea67fSPeter Grehan * 448b9dea67fSPeter Grehan * 'The first 18 words (72 bytes) of the PLT are reserved for 449b9dea67fSPeter Grehan * use by the dynamic linker. 450b9dea67fSPeter Grehan * ... 451b9dea67fSPeter Grehan * 'If the executable or shared object requires N procedure 452b9dea67fSPeter Grehan * linkage table entries, the link editor shall reserve 3*N 453b9dea67fSPeter Grehan * words (12*N bytes) following the 18 reserved words. The 454b9dea67fSPeter Grehan * first 2*N of these words are the procedure linkage table 455b9dea67fSPeter Grehan * entries themselves. The static linker directs calls to bytes 456b9dea67fSPeter Grehan * (72 + (i-1)*8), for i between 1 and N inclusive. The remaining 457b9dea67fSPeter Grehan * N words (4*N bytes) are reserved for use by the dynamic linker.' 458b9dea67fSPeter Grehan */ 459b9dea67fSPeter Grehan 460b9dea67fSPeter Grehan /* 461b9dea67fSPeter Grehan * Copy the absolute-call assembler stub into the first part of 462b9dea67fSPeter Grehan * the reserved PLT area. 463b9dea67fSPeter Grehan */ 464b9dea67fSPeter Grehan memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); 465b9dea67fSPeter Grehan 466b9dea67fSPeter Grehan /* 467b9dea67fSPeter Grehan * Determine the address of the jumptable, which is the dyn-linker 468b9dea67fSPeter Grehan * reserved area after the call cells. Write the absolute address 469b9dea67fSPeter Grehan * of the jumptable into the absolute-call assembler code so it 470b9dea67fSPeter Grehan * can determine this address. 471b9dea67fSPeter Grehan */ 472b9dea67fSPeter Grehan jmptab = pltcall + 18 + N * 2; 473b9dea67fSPeter Grehan pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */ 474b9dea67fSPeter Grehan pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */ 475b9dea67fSPeter Grehan 476b9dea67fSPeter Grehan /* 477b9dea67fSPeter Grehan * Skip down 32 bytes into the initial reserved area and copy 478b9dea67fSPeter Grehan * in the standard resolving assembler call. Into this assembler, 479b9dea67fSPeter Grehan * insert the absolute address of the _rtld_bind_start routine 480b9dea67fSPeter Grehan * and the address of the relocation object. 481b9dea67fSPeter Grehan */ 482b9dea67fSPeter Grehan pltresolve = obj->pltgot + 8; 483b9dea67fSPeter Grehan 484b9dea67fSPeter Grehan memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); 485b9dea67fSPeter Grehan pltresolve[0] |= _ppc_ha(_rtld_bind_start); 486b9dea67fSPeter Grehan pltresolve[1] |= _ppc_la(_rtld_bind_start); 487b9dea67fSPeter Grehan pltresolve[3] |= _ppc_ha(obj); 488b9dea67fSPeter Grehan pltresolve[4] |= _ppc_la(obj); 489b9dea67fSPeter Grehan 490b9dea67fSPeter Grehan /* 491b9dea67fSPeter Grehan * Sync the icache for the byte range represented by the 492b9dea67fSPeter Grehan * trampoline routines and call slots. 493b9dea67fSPeter Grehan */ 494b9dea67fSPeter Grehan __syncicache(pltcall, 72 + N * 8); 495b9dea67fSPeter Grehan } 496