127bd4146SNathan Whitehorn /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 227bd4146SNathan Whitehorn 327bd4146SNathan Whitehorn /*- 427bd4146SNathan Whitehorn * Copyright (C) 1998 Tsubai Masanari 527bd4146SNathan Whitehorn * All rights reserved. 627bd4146SNathan Whitehorn * 727bd4146SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 827bd4146SNathan Whitehorn * modification, are permitted provided that the following conditions 927bd4146SNathan Whitehorn * are met: 1027bd4146SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 1127bd4146SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 1227bd4146SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 1327bd4146SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 1427bd4146SNathan Whitehorn * documentation and/or other materials provided with the distribution. 1527bd4146SNathan Whitehorn * 3. The name of the author may not be used to endorse or promote products 1627bd4146SNathan Whitehorn * derived from this software without specific prior written permission. 1727bd4146SNathan Whitehorn * 1827bd4146SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1927bd4146SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2027bd4146SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2127bd4146SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2227bd4146SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2327bd4146SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2427bd4146SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2527bd4146SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2627bd4146SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2727bd4146SNathan Whitehorn * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2827bd4146SNathan Whitehorn * 2927bd4146SNathan Whitehorn * $FreeBSD$ 3027bd4146SNathan Whitehorn */ 3127bd4146SNathan Whitehorn 3227bd4146SNathan Whitehorn #include <sys/param.h> 3327bd4146SNathan Whitehorn #include <sys/mman.h> 3427bd4146SNathan Whitehorn 3527bd4146SNathan Whitehorn #include <errno.h> 3627bd4146SNathan Whitehorn #include <stdio.h> 3727bd4146SNathan Whitehorn #include <stdlib.h> 3827bd4146SNathan Whitehorn #include <string.h> 3927bd4146SNathan Whitehorn #include <unistd.h> 4027bd4146SNathan Whitehorn #include <machine/cpu.h> 4127bd4146SNathan Whitehorn #include <machine/md_var.h> 4227bd4146SNathan Whitehorn 4327bd4146SNathan Whitehorn #include "debug.h" 4427bd4146SNathan Whitehorn #include "rtld.h" 4527bd4146SNathan Whitehorn 4627bd4146SNathan Whitehorn struct funcdesc { 4727bd4146SNathan Whitehorn Elf_Addr addr; 4827bd4146SNathan Whitehorn Elf_Addr toc; 4927bd4146SNathan Whitehorn Elf_Addr env; 5027bd4146SNathan Whitehorn }; 5127bd4146SNathan Whitehorn 5227bd4146SNathan Whitehorn /* 5327bd4146SNathan Whitehorn * Process the R_PPC_COPY relocations 5427bd4146SNathan Whitehorn */ 5527bd4146SNathan Whitehorn int 5627bd4146SNathan Whitehorn do_copy_relocations(Obj_Entry *dstobj) 5727bd4146SNathan Whitehorn { 5827bd4146SNathan Whitehorn const Elf_Rela *relalim; 5927bd4146SNathan Whitehorn const Elf_Rela *rela; 6027bd4146SNathan Whitehorn 6127bd4146SNathan Whitehorn /* 6227bd4146SNathan Whitehorn * COPY relocs are invalid outside of the main program 6327bd4146SNathan Whitehorn */ 6427bd4146SNathan Whitehorn assert(dstobj->mainprog); 6527bd4146SNathan Whitehorn 6627bd4146SNathan Whitehorn relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + 6727bd4146SNathan Whitehorn dstobj->relasize); 6827bd4146SNathan Whitehorn for (rela = dstobj->rela; rela < relalim; rela++) { 6927bd4146SNathan Whitehorn void *dstaddr; 7027bd4146SNathan Whitehorn const Elf_Sym *dstsym; 7127bd4146SNathan Whitehorn const char *name; 7227bd4146SNathan Whitehorn unsigned long hash; 7327bd4146SNathan Whitehorn size_t size; 7427bd4146SNathan Whitehorn const void *srcaddr; 7527bd4146SNathan Whitehorn const Elf_Sym *srcsym = NULL; 7627bd4146SNathan Whitehorn Obj_Entry *srcobj; 7727bd4146SNathan Whitehorn const Ver_Entry *ve; 7827bd4146SNathan Whitehorn 7927bd4146SNathan Whitehorn if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 8027bd4146SNathan Whitehorn continue; 8127bd4146SNathan Whitehorn } 8227bd4146SNathan Whitehorn 8327bd4146SNathan Whitehorn dstaddr = (void *) (dstobj->relocbase + rela->r_offset); 8427bd4146SNathan Whitehorn dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 8527bd4146SNathan Whitehorn name = dstobj->strtab + dstsym->st_name; 8627bd4146SNathan Whitehorn hash = elf_hash(name); 8727bd4146SNathan Whitehorn size = dstsym->st_size; 8827bd4146SNathan Whitehorn ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 8927bd4146SNathan Whitehorn 9027bd4146SNathan Whitehorn for (srcobj = dstobj->next; srcobj != NULL; 9127bd4146SNathan Whitehorn srcobj = srcobj->next) { 9227bd4146SNathan Whitehorn if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) 9327bd4146SNathan Whitehorn != NULL) { 9427bd4146SNathan Whitehorn break; 9527bd4146SNathan Whitehorn } 9627bd4146SNathan Whitehorn } 9727bd4146SNathan Whitehorn 9827bd4146SNathan Whitehorn if (srcobj == NULL) { 9927bd4146SNathan Whitehorn _rtld_error("Undefined symbol \"%s\" " 10027bd4146SNathan Whitehorn " referenced from COPY" 10127bd4146SNathan Whitehorn " relocation in %s", name, dstobj->path); 10227bd4146SNathan Whitehorn return (-1); 10327bd4146SNathan Whitehorn } 10427bd4146SNathan Whitehorn 10527bd4146SNathan Whitehorn srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value); 10627bd4146SNathan Whitehorn memcpy(dstaddr, srcaddr, size); 10727bd4146SNathan Whitehorn dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); 10827bd4146SNathan Whitehorn } 10927bd4146SNathan Whitehorn 11027bd4146SNathan Whitehorn return (0); 11127bd4146SNathan Whitehorn } 11227bd4146SNathan Whitehorn 11327bd4146SNathan Whitehorn 11427bd4146SNathan Whitehorn /* 11527bd4146SNathan Whitehorn * Perform early relocation of the run-time linker image 11627bd4146SNathan Whitehorn */ 11727bd4146SNathan Whitehorn void 11827bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 11927bd4146SNathan Whitehorn { 12027bd4146SNathan Whitehorn const Elf_Rela *rela = 0, *relalim; 12127bd4146SNathan Whitehorn Elf_Addr relasz = 0; 12227bd4146SNathan Whitehorn Elf_Addr *where; 12327bd4146SNathan Whitehorn 12427bd4146SNathan Whitehorn /* 12527bd4146SNathan Whitehorn * Extract the rela/relasz values from the dynamic section 12627bd4146SNathan Whitehorn */ 12727bd4146SNathan Whitehorn for (; dynp->d_tag != DT_NULL; dynp++) { 12827bd4146SNathan Whitehorn switch (dynp->d_tag) { 12927bd4146SNathan Whitehorn case DT_RELA: 13027bd4146SNathan Whitehorn rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 13127bd4146SNathan Whitehorn break; 13227bd4146SNathan Whitehorn case DT_RELASZ: 13327bd4146SNathan Whitehorn relasz = dynp->d_un.d_val; 13427bd4146SNathan Whitehorn break; 13527bd4146SNathan Whitehorn } 13627bd4146SNathan Whitehorn } 13727bd4146SNathan Whitehorn 13827bd4146SNathan Whitehorn /* 13927bd4146SNathan Whitehorn * Relocate these values 14027bd4146SNathan Whitehorn */ 14127bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 14227bd4146SNathan Whitehorn for (; rela < relalim; rela++) { 14327bd4146SNathan Whitehorn where = (Elf_Addr *)(relocbase + rela->r_offset); 14427bd4146SNathan Whitehorn *where = (Elf_Addr)(relocbase + rela->r_addend); 14527bd4146SNathan Whitehorn } 14627bd4146SNathan Whitehorn } 14727bd4146SNathan Whitehorn 14827bd4146SNathan Whitehorn 14927bd4146SNathan Whitehorn /* 15027bd4146SNathan Whitehorn * Relocate a non-PLT object with addend. 15127bd4146SNathan Whitehorn */ 15227bd4146SNathan Whitehorn static int 15327bd4146SNathan Whitehorn reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 15427bd4146SNathan Whitehorn SymCache *cache) 15527bd4146SNathan Whitehorn { 15627bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 15727bd4146SNathan Whitehorn const Elf_Sym *def; 15827bd4146SNathan Whitehorn const Obj_Entry *defobj; 15927bd4146SNathan Whitehorn Elf_Addr tmp; 16027bd4146SNathan Whitehorn 16127bd4146SNathan Whitehorn switch (ELF_R_TYPE(rela->r_info)) { 16227bd4146SNathan Whitehorn 16327bd4146SNathan Whitehorn case R_PPC_NONE: 16427bd4146SNathan Whitehorn break; 16527bd4146SNathan Whitehorn 16627bd4146SNathan Whitehorn case R_PPC64_ADDR64: /* doubleword64 S + A */ 16727bd4146SNathan Whitehorn case R_PPC_GLOB_DAT: 16827bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 16927bd4146SNathan Whitehorn false, cache); 17027bd4146SNathan Whitehorn if (def == NULL) { 17127bd4146SNathan Whitehorn return (-1); 17227bd4146SNathan Whitehorn } 17327bd4146SNathan Whitehorn 17427bd4146SNathan Whitehorn tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 17527bd4146SNathan Whitehorn rela->r_addend); 17627bd4146SNathan Whitehorn 17727bd4146SNathan Whitehorn /* Don't issue write if unnecessary; avoid COW page fault */ 17827bd4146SNathan Whitehorn if (*where != tmp) { 17927bd4146SNathan Whitehorn *where = tmp; 18027bd4146SNathan Whitehorn } 18127bd4146SNathan Whitehorn break; 18227bd4146SNathan Whitehorn 18327bd4146SNathan Whitehorn case R_PPC_RELATIVE: /* doubleword64 B + A */ 18427bd4146SNathan Whitehorn tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 18527bd4146SNathan Whitehorn 18627bd4146SNathan Whitehorn /* As above, don't issue write unnecessarily */ 18727bd4146SNathan Whitehorn if (*where != tmp) { 18827bd4146SNathan Whitehorn *where = tmp; 18927bd4146SNathan Whitehorn } 19027bd4146SNathan Whitehorn break; 19127bd4146SNathan Whitehorn 19227bd4146SNathan Whitehorn case R_PPC_COPY: 19327bd4146SNathan Whitehorn /* 19427bd4146SNathan Whitehorn * These are deferred until all other relocations 19527bd4146SNathan Whitehorn * have been done. All we do here is make sure 19627bd4146SNathan Whitehorn * that the COPY relocation is not in a shared 19727bd4146SNathan Whitehorn * library. They are allowed only in executable 19827bd4146SNathan Whitehorn * files. 19927bd4146SNathan Whitehorn */ 20027bd4146SNathan Whitehorn if (!obj->mainprog) { 20127bd4146SNathan Whitehorn _rtld_error("%s: Unexpected R_COPY " 20227bd4146SNathan Whitehorn " relocation in shared library", 20327bd4146SNathan Whitehorn obj->path); 20427bd4146SNathan Whitehorn return (-1); 20527bd4146SNathan Whitehorn } 20627bd4146SNathan Whitehorn break; 20727bd4146SNathan Whitehorn 20827bd4146SNathan Whitehorn case R_PPC_JMP_SLOT: 20927bd4146SNathan Whitehorn /* 21027bd4146SNathan Whitehorn * These will be handled by the plt/jmpslot routines 21127bd4146SNathan Whitehorn */ 21227bd4146SNathan Whitehorn break; 21327bd4146SNathan Whitehorn 21427bd4146SNathan Whitehorn case R_PPC64_DTPMOD64: 21527bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 21627bd4146SNathan Whitehorn false, cache); 21727bd4146SNathan Whitehorn 21827bd4146SNathan Whitehorn if (def == NULL) 21927bd4146SNathan Whitehorn return (-1); 22027bd4146SNathan Whitehorn 22127bd4146SNathan Whitehorn *where = (Elf_Addr) defobj->tlsindex; 22227bd4146SNathan Whitehorn 22327bd4146SNathan Whitehorn break; 22427bd4146SNathan Whitehorn 22527bd4146SNathan Whitehorn case R_PPC64_TPREL64: 22627bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 22727bd4146SNathan Whitehorn false, cache); 22827bd4146SNathan Whitehorn 22927bd4146SNathan Whitehorn if (def == NULL) 23027bd4146SNathan Whitehorn return (-1); 23127bd4146SNathan Whitehorn 23227bd4146SNathan Whitehorn /* 23327bd4146SNathan Whitehorn * We lazily allocate offsets for static TLS as we 23427bd4146SNathan Whitehorn * see the first relocation that references the 23527bd4146SNathan Whitehorn * TLS block. This allows us to support (small 23627bd4146SNathan Whitehorn * amounts of) static TLS in dynamically loaded 23727bd4146SNathan Whitehorn * modules. If we run out of space, we generate an 23827bd4146SNathan Whitehorn * error. 23927bd4146SNathan Whitehorn */ 24027bd4146SNathan Whitehorn if (!defobj->tls_done) { 24127bd4146SNathan Whitehorn if (!allocate_tls_offset((Obj_Entry*) defobj)) { 24227bd4146SNathan Whitehorn _rtld_error("%s: No space available for static " 24327bd4146SNathan Whitehorn "Thread Local Storage", obj->path); 24427bd4146SNathan Whitehorn return (-1); 24527bd4146SNathan Whitehorn } 24627bd4146SNathan Whitehorn } 24727bd4146SNathan Whitehorn 24827bd4146SNathan Whitehorn *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 24927bd4146SNathan Whitehorn + (Elf_Addr *)(def->st_value + rela->r_addend 25027bd4146SNathan Whitehorn + defobj->tlsoffset - TLS_TP_OFFSET); 25127bd4146SNathan Whitehorn 25227bd4146SNathan Whitehorn break; 25327bd4146SNathan Whitehorn 25427bd4146SNathan Whitehorn case R_PPC64_DTPREL64: 25527bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 25627bd4146SNathan Whitehorn false, cache); 25727bd4146SNathan Whitehorn 25827bd4146SNathan Whitehorn if (def == NULL) 25927bd4146SNathan Whitehorn return (-1); 26027bd4146SNathan Whitehorn 26127bd4146SNathan Whitehorn *where += (Elf_Addr)(def->st_value + rela->r_addend 26227bd4146SNathan Whitehorn - TLS_DTV_OFFSET); 26327bd4146SNathan Whitehorn 26427bd4146SNathan Whitehorn break; 26527bd4146SNathan Whitehorn 26627bd4146SNathan Whitehorn default: 26727bd4146SNathan Whitehorn _rtld_error("%s: Unsupported relocation type %ld" 26827bd4146SNathan Whitehorn " in non-PLT relocations\n", obj->path, 26927bd4146SNathan Whitehorn ELF_R_TYPE(rela->r_info)); 27027bd4146SNathan Whitehorn return (-1); 27127bd4146SNathan Whitehorn } 27227bd4146SNathan Whitehorn return (0); 27327bd4146SNathan Whitehorn } 27427bd4146SNathan Whitehorn 27527bd4146SNathan Whitehorn 27627bd4146SNathan Whitehorn /* 27727bd4146SNathan Whitehorn * Process non-PLT relocations 27827bd4146SNathan Whitehorn */ 27927bd4146SNathan Whitehorn int 28027bd4146SNathan Whitehorn reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) 28127bd4146SNathan Whitehorn { 28227bd4146SNathan Whitehorn const Elf_Rela *relalim; 28327bd4146SNathan Whitehorn const Elf_Rela *rela; 28427bd4146SNathan Whitehorn SymCache *cache; 28527bd4146SNathan Whitehorn int bytes = obj->nchains * sizeof(SymCache); 28627bd4146SNathan Whitehorn int r = -1; 28727bd4146SNathan Whitehorn 28827bd4146SNathan Whitehorn /* 28927bd4146SNathan Whitehorn * The dynamic loader may be called from a thread, we have 29027bd4146SNathan Whitehorn * limited amounts of stack available so we cannot use alloca(). 29127bd4146SNathan Whitehorn */ 29227bd4146SNathan Whitehorn if (obj != obj_rtld) { 29327bd4146SNathan Whitehorn cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 29427bd4146SNathan Whitehorn -1, 0); 29527bd4146SNathan Whitehorn if (cache == MAP_FAILED) 29627bd4146SNathan Whitehorn cache = NULL; 29727bd4146SNathan Whitehorn } else 29827bd4146SNathan Whitehorn cache = NULL; 29927bd4146SNathan Whitehorn 30027bd4146SNathan Whitehorn /* 30127bd4146SNathan Whitehorn * From the SVR4 PPC ABI: 30227bd4146SNathan Whitehorn * "The PowerPC family uses only the Elf32_Rela relocation 30327bd4146SNathan Whitehorn * entries with explicit addends." 30427bd4146SNathan Whitehorn */ 30527bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 30627bd4146SNathan Whitehorn for (rela = obj->rela; rela < relalim; rela++) { 30727bd4146SNathan Whitehorn if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0) 30827bd4146SNathan Whitehorn goto done; 30927bd4146SNathan Whitehorn } 31027bd4146SNathan Whitehorn r = 0; 31127bd4146SNathan Whitehorn done: 31227bd4146SNathan Whitehorn if (cache) { 31327bd4146SNathan Whitehorn munmap(cache, bytes); 31427bd4146SNathan Whitehorn } 31527bd4146SNathan Whitehorn return (r); 31627bd4146SNathan Whitehorn } 31727bd4146SNathan Whitehorn 31827bd4146SNathan Whitehorn 31927bd4146SNathan Whitehorn /* 32027bd4146SNathan Whitehorn * Initialise a PLT slot to the resolving trampoline 32127bd4146SNathan Whitehorn */ 32227bd4146SNathan Whitehorn static int 32327bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 32427bd4146SNathan Whitehorn { 32527bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 32627bd4146SNathan Whitehorn Elf_Addr *glink; 32727bd4146SNathan Whitehorn long reloff; 32827bd4146SNathan Whitehorn 32927bd4146SNathan Whitehorn reloff = rela - obj->pltrela; 33027bd4146SNathan Whitehorn 33127bd4146SNathan Whitehorn if (obj->priv == NULL) 33227bd4146SNathan Whitehorn obj->priv = malloc(obj->pltrelasize); 33327bd4146SNathan Whitehorn glink = obj->priv + reloff*sizeof(Elf_Addr)*2; 33427bd4146SNathan Whitehorn 33527bd4146SNathan Whitehorn if ((reloff < 0) || (reloff >= 0x8000)) { 33627bd4146SNathan Whitehorn return (-1); 33727bd4146SNathan Whitehorn } 33827bd4146SNathan Whitehorn 33927bd4146SNathan Whitehorn dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%p", (void *)where, reloff, glink); 34027bd4146SNathan Whitehorn 34127bd4146SNathan Whitehorn memcpy(where, _rtld_bind_start, sizeof(struct funcdesc)); 34227bd4146SNathan Whitehorn ((struct funcdesc *)(where))->env = (Elf_Addr)glink; 34327bd4146SNathan Whitehorn *(glink++) = (Elf_Addr)obj; 34427bd4146SNathan Whitehorn *(glink++) = reloff*sizeof(Elf_Rela); 34527bd4146SNathan Whitehorn 34627bd4146SNathan Whitehorn return (0); 34727bd4146SNathan Whitehorn } 34827bd4146SNathan Whitehorn 34927bd4146SNathan Whitehorn 35027bd4146SNathan Whitehorn /* 35127bd4146SNathan Whitehorn * Process the PLT relocations. 35227bd4146SNathan Whitehorn */ 35327bd4146SNathan Whitehorn int 35427bd4146SNathan Whitehorn reloc_plt(Obj_Entry *obj) 35527bd4146SNathan Whitehorn { 35627bd4146SNathan Whitehorn const Elf_Rela *relalim; 35727bd4146SNathan Whitehorn const Elf_Rela *rela; 35827bd4146SNathan Whitehorn 35927bd4146SNathan Whitehorn if (obj->pltrelasize != 0) { 36027bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((char *)obj->pltrela + 36127bd4146SNathan Whitehorn obj->pltrelasize); 36227bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 36327bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 36427bd4146SNathan Whitehorn 36527bd4146SNathan Whitehorn if (reloc_plt_object(obj, rela) < 0) { 36627bd4146SNathan Whitehorn return (-1); 36727bd4146SNathan Whitehorn } 36827bd4146SNathan Whitehorn } 36927bd4146SNathan Whitehorn } 37027bd4146SNathan Whitehorn 37127bd4146SNathan Whitehorn return (0); 37227bd4146SNathan Whitehorn } 37327bd4146SNathan Whitehorn 37427bd4146SNathan Whitehorn 37527bd4146SNathan Whitehorn /* 37627bd4146SNathan Whitehorn * LD_BIND_NOW was set - force relocation for all jump slots 37727bd4146SNathan Whitehorn */ 37827bd4146SNathan Whitehorn int 37927bd4146SNathan Whitehorn reloc_jmpslots(Obj_Entry *obj) 38027bd4146SNathan Whitehorn { 38127bd4146SNathan Whitehorn const Obj_Entry *defobj; 38227bd4146SNathan Whitehorn const Elf_Rela *relalim; 38327bd4146SNathan Whitehorn const Elf_Rela *rela; 38427bd4146SNathan Whitehorn const Elf_Sym *def; 38527bd4146SNathan Whitehorn Elf_Addr *where; 38627bd4146SNathan Whitehorn Elf_Addr target; 38727bd4146SNathan Whitehorn 38827bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 38927bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 39027bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 39127bd4146SNathan Whitehorn where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 39227bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 39327bd4146SNathan Whitehorn true, NULL); 39427bd4146SNathan Whitehorn if (def == NULL) { 39527bd4146SNathan Whitehorn dbg("reloc_jmpslots: sym not found"); 39627bd4146SNathan Whitehorn return (-1); 39727bd4146SNathan Whitehorn } 39827bd4146SNathan Whitehorn 39927bd4146SNathan Whitehorn target = (Elf_Addr)(defobj->relocbase + def->st_value); 40027bd4146SNathan Whitehorn 40127bd4146SNathan Whitehorn #if 0 40227bd4146SNathan Whitehorn /* PG XXX */ 40327bd4146SNathan Whitehorn dbg("\"%s\" in \"%s\" --> %p in \"%s\"", 40427bd4146SNathan Whitehorn defobj->strtab + def->st_name, basename(obj->path), 40527bd4146SNathan Whitehorn (void *)target, basename(defobj->path)); 40627bd4146SNathan Whitehorn #endif 40727bd4146SNathan Whitehorn 408*d48dde6fSNathan Whitehorn if (def == &sym_zero) { 409*d48dde6fSNathan Whitehorn /* Zero undefined weak symbols */ 410*d48dde6fSNathan Whitehorn bzero(where, sizeof(struct funcdesc)); 411*d48dde6fSNathan Whitehorn } else { 41227bd4146SNathan Whitehorn reloc_jmpslot(where, target, defobj, obj, 41327bd4146SNathan Whitehorn (const Elf_Rel *) rela); 41427bd4146SNathan Whitehorn } 415*d48dde6fSNathan Whitehorn } 41627bd4146SNathan Whitehorn 41727bd4146SNathan Whitehorn obj->jmpslots_done = true; 41827bd4146SNathan Whitehorn 41927bd4146SNathan Whitehorn return (0); 42027bd4146SNathan Whitehorn } 42127bd4146SNathan Whitehorn 42227bd4146SNathan Whitehorn 42327bd4146SNathan Whitehorn /* 42427bd4146SNathan Whitehorn * Update the value of a PLT jump slot. 42527bd4146SNathan Whitehorn */ 42627bd4146SNathan Whitehorn Elf_Addr 42727bd4146SNathan Whitehorn reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, 42827bd4146SNathan Whitehorn const Obj_Entry *obj, const Elf_Rel *rel) 42927bd4146SNathan Whitehorn { 43027bd4146SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", 43127bd4146SNathan Whitehorn (void *)wherep, (void *)target, *(Elf_Addr *)target, 43227bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase); 43327bd4146SNathan Whitehorn 43427bd4146SNathan Whitehorn /* 43527bd4146SNathan Whitehorn * At the PLT entry pointed at by `wherep', construct 43627bd4146SNathan Whitehorn * a direct transfer to the now fully resolved function 43727bd4146SNathan Whitehorn * address. 43827bd4146SNathan Whitehorn */ 43927bd4146SNathan Whitehorn 44027bd4146SNathan Whitehorn memcpy(wherep, (void *)target, sizeof(struct funcdesc)); 44127bd4146SNathan Whitehorn if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { 44227bd4146SNathan Whitehorn /* 44327bd4146SNathan Whitehorn * XXX: It is possible (e.g. LD_BIND_NOW) that the function 44427bd4146SNathan Whitehorn * descriptor we are copying has not yet been relocated. 44527bd4146SNathan Whitehorn * If this happens, fix it. 44627bd4146SNathan Whitehorn */ 44727bd4146SNathan Whitehorn 44827bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->addr += 44927bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 45027bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->toc += 45127bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 45227bd4146SNathan Whitehorn } 45327bd4146SNathan Whitehorn 45427bd4146SNathan Whitehorn __asm __volatile("dcbst 0,%0; sync" :: "r"(wherep) : "memory"); 45527bd4146SNathan Whitehorn 45627bd4146SNathan Whitehorn return (target); 45727bd4146SNathan Whitehorn } 45827bd4146SNathan Whitehorn 45927bd4146SNathan Whitehorn void 46027bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj) 46127bd4146SNathan Whitehorn { 46227bd4146SNathan Whitehorn } 46327bd4146SNathan Whitehorn 46427bd4146SNathan Whitehorn void 46527bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list) 46627bd4146SNathan Whitehorn { 46727bd4146SNathan Whitehorn register Elf_Addr **tp __asm__("r13"); 46827bd4146SNathan Whitehorn Elf_Addr **_tp; 46927bd4146SNathan Whitehorn 47027bd4146SNathan Whitehorn /* 47127bd4146SNathan Whitehorn * Fix the size of the static TLS block by using the maximum 47227bd4146SNathan Whitehorn * offset allocated so far and adding a bit for dynamic modules to 47327bd4146SNathan Whitehorn * use. 47427bd4146SNathan Whitehorn */ 47527bd4146SNathan Whitehorn 47627bd4146SNathan Whitehorn tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 47727bd4146SNathan Whitehorn 47827bd4146SNathan Whitehorn _tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16) 47927bd4146SNathan Whitehorn + TLS_TP_OFFSET + TLS_TCB_SIZE); 48027bd4146SNathan Whitehorn 48127bd4146SNathan Whitehorn /* 48227bd4146SNathan Whitehorn * XXX gcc seems to ignore 'tp = _tp;' 48327bd4146SNathan Whitehorn */ 48427bd4146SNathan Whitehorn 48527bd4146SNathan Whitehorn __asm __volatile("mr %0,%1" : "=r"(tp) : "r"(_tp)); 48627bd4146SNathan Whitehorn } 48727bd4146SNathan Whitehorn 48827bd4146SNathan Whitehorn void* 48927bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti) 49027bd4146SNathan Whitehorn { 49127bd4146SNathan Whitehorn register Elf_Addr **tp __asm__("r13"); 49227bd4146SNathan Whitehorn char *p; 49327bd4146SNathan Whitehorn 49427bd4146SNathan Whitehorn p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 49527bd4146SNathan Whitehorn - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); 49627bd4146SNathan Whitehorn 49727bd4146SNathan Whitehorn return (p + TLS_DTV_OFFSET); 49827bd4146SNathan Whitehorn } 499