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 size_t size; 7327bd4146SNathan Whitehorn const void *srcaddr; 7427bd4146SNathan Whitehorn const Elf_Sym *srcsym = NULL; 758569deafSKonstantin Belousov const Obj_Entry *srcobj, *defobj; 768569deafSKonstantin Belousov SymLook req; 778569deafSKonstantin Belousov int res; 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 size = dstsym->st_size; 878569deafSKonstantin Belousov symlook_init(&req, name); 888569deafSKonstantin Belousov req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 89*082f959aSKonstantin Belousov req.flags = SYMLOOK_EARLY; 9027bd4146SNathan Whitehorn 9127bd4146SNathan Whitehorn for (srcobj = dstobj->next; srcobj != NULL; 9227bd4146SNathan Whitehorn srcobj = srcobj->next) { 938569deafSKonstantin Belousov res = symlook_obj(&req, srcobj); 948569deafSKonstantin Belousov if (res == 0) { 958569deafSKonstantin Belousov srcsym = req.sym_out; 968569deafSKonstantin Belousov defobj = req.defobj_out; 9727bd4146SNathan Whitehorn break; 9827bd4146SNathan Whitehorn } 9927bd4146SNathan Whitehorn } 10027bd4146SNathan Whitehorn 10127bd4146SNathan Whitehorn if (srcobj == NULL) { 10227bd4146SNathan Whitehorn _rtld_error("Undefined symbol \"%s\" " 10327bd4146SNathan Whitehorn " referenced from COPY" 10427bd4146SNathan Whitehorn " relocation in %s", name, dstobj->path); 10527bd4146SNathan Whitehorn return (-1); 10627bd4146SNathan Whitehorn } 10727bd4146SNathan Whitehorn 1088569deafSKonstantin Belousov srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); 10927bd4146SNathan Whitehorn memcpy(dstaddr, srcaddr, size); 11027bd4146SNathan Whitehorn dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); 11127bd4146SNathan Whitehorn } 11227bd4146SNathan Whitehorn 11327bd4146SNathan Whitehorn return (0); 11427bd4146SNathan Whitehorn } 11527bd4146SNathan Whitehorn 11627bd4146SNathan Whitehorn 11727bd4146SNathan Whitehorn /* 11827bd4146SNathan Whitehorn * Perform early relocation of the run-time linker image 11927bd4146SNathan Whitehorn */ 12027bd4146SNathan Whitehorn void 12127bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 12227bd4146SNathan Whitehorn { 12327bd4146SNathan Whitehorn const Elf_Rela *rela = 0, *relalim; 12427bd4146SNathan Whitehorn Elf_Addr relasz = 0; 12527bd4146SNathan Whitehorn Elf_Addr *where; 12627bd4146SNathan Whitehorn 12727bd4146SNathan Whitehorn /* 12827bd4146SNathan Whitehorn * Extract the rela/relasz values from the dynamic section 12927bd4146SNathan Whitehorn */ 13027bd4146SNathan Whitehorn for (; dynp->d_tag != DT_NULL; dynp++) { 13127bd4146SNathan Whitehorn switch (dynp->d_tag) { 13227bd4146SNathan Whitehorn case DT_RELA: 13327bd4146SNathan Whitehorn rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 13427bd4146SNathan Whitehorn break; 13527bd4146SNathan Whitehorn case DT_RELASZ: 13627bd4146SNathan Whitehorn relasz = dynp->d_un.d_val; 13727bd4146SNathan Whitehorn break; 13827bd4146SNathan Whitehorn } 13927bd4146SNathan Whitehorn } 14027bd4146SNathan Whitehorn 14127bd4146SNathan Whitehorn /* 14227bd4146SNathan Whitehorn * Relocate these values 14327bd4146SNathan Whitehorn */ 14427bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 14527bd4146SNathan Whitehorn for (; rela < relalim; rela++) { 14627bd4146SNathan Whitehorn where = (Elf_Addr *)(relocbase + rela->r_offset); 14727bd4146SNathan Whitehorn *where = (Elf_Addr)(relocbase + rela->r_addend); 14827bd4146SNathan Whitehorn } 14927bd4146SNathan Whitehorn } 15027bd4146SNathan Whitehorn 15127bd4146SNathan Whitehorn 15227bd4146SNathan Whitehorn /* 15327bd4146SNathan Whitehorn * Relocate a non-PLT object with addend. 15427bd4146SNathan Whitehorn */ 15527bd4146SNathan Whitehorn static int 15627bd4146SNathan Whitehorn reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 157*082f959aSKonstantin Belousov SymCache *cache, int flags, RtldLockState *lockstate) 15827bd4146SNathan Whitehorn { 15927bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 16027bd4146SNathan Whitehorn const Elf_Sym *def; 16127bd4146SNathan Whitehorn const Obj_Entry *defobj; 16227bd4146SNathan Whitehorn Elf_Addr tmp; 16327bd4146SNathan Whitehorn 16427bd4146SNathan Whitehorn switch (ELF_R_TYPE(rela->r_info)) { 16527bd4146SNathan Whitehorn 16627bd4146SNathan Whitehorn case R_PPC_NONE: 16727bd4146SNathan Whitehorn break; 16827bd4146SNathan Whitehorn 1699cc92083SNathan Whitehorn case R_PPC64_UADDR64: /* doubleword64 S + A */ 1709cc92083SNathan Whitehorn case R_PPC64_ADDR64: 17127bd4146SNathan Whitehorn case R_PPC_GLOB_DAT: 17227bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 173*082f959aSKonstantin Belousov flags, cache, lockstate); 17427bd4146SNathan Whitehorn if (def == NULL) { 17527bd4146SNathan Whitehorn return (-1); 17627bd4146SNathan Whitehorn } 17727bd4146SNathan Whitehorn 17827bd4146SNathan Whitehorn tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 17927bd4146SNathan Whitehorn rela->r_addend); 18027bd4146SNathan Whitehorn 18127bd4146SNathan Whitehorn /* Don't issue write if unnecessary; avoid COW page fault */ 18227bd4146SNathan Whitehorn if (*where != tmp) { 18327bd4146SNathan Whitehorn *where = tmp; 18427bd4146SNathan Whitehorn } 18527bd4146SNathan Whitehorn break; 18627bd4146SNathan Whitehorn 18727bd4146SNathan Whitehorn case R_PPC_RELATIVE: /* doubleword64 B + A */ 18827bd4146SNathan Whitehorn tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 18927bd4146SNathan Whitehorn 19027bd4146SNathan Whitehorn /* As above, don't issue write unnecessarily */ 19127bd4146SNathan Whitehorn if (*where != tmp) { 19227bd4146SNathan Whitehorn *where = tmp; 19327bd4146SNathan Whitehorn } 19427bd4146SNathan Whitehorn break; 19527bd4146SNathan Whitehorn 19627bd4146SNathan Whitehorn case R_PPC_COPY: 19727bd4146SNathan Whitehorn /* 19827bd4146SNathan Whitehorn * These are deferred until all other relocations 19927bd4146SNathan Whitehorn * have been done. All we do here is make sure 20027bd4146SNathan Whitehorn * that the COPY relocation is not in a shared 20127bd4146SNathan Whitehorn * library. They are allowed only in executable 20227bd4146SNathan Whitehorn * files. 20327bd4146SNathan Whitehorn */ 20427bd4146SNathan Whitehorn if (!obj->mainprog) { 20527bd4146SNathan Whitehorn _rtld_error("%s: Unexpected R_COPY " 20627bd4146SNathan Whitehorn " relocation in shared library", 20727bd4146SNathan Whitehorn obj->path); 20827bd4146SNathan Whitehorn return (-1); 20927bd4146SNathan Whitehorn } 21027bd4146SNathan Whitehorn break; 21127bd4146SNathan Whitehorn 21227bd4146SNathan Whitehorn case R_PPC_JMP_SLOT: 21327bd4146SNathan Whitehorn /* 21427bd4146SNathan Whitehorn * These will be handled by the plt/jmpslot routines 21527bd4146SNathan Whitehorn */ 21627bd4146SNathan Whitehorn break; 21727bd4146SNathan Whitehorn 21827bd4146SNathan Whitehorn case R_PPC64_DTPMOD64: 21927bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 220*082f959aSKonstantin Belousov flags, cache, lockstate); 22127bd4146SNathan Whitehorn 22227bd4146SNathan Whitehorn if (def == NULL) 22327bd4146SNathan Whitehorn return (-1); 22427bd4146SNathan Whitehorn 22527bd4146SNathan Whitehorn *where = (Elf_Addr) defobj->tlsindex; 22627bd4146SNathan Whitehorn 22727bd4146SNathan Whitehorn break; 22827bd4146SNathan Whitehorn 22927bd4146SNathan Whitehorn case R_PPC64_TPREL64: 23027bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 231*082f959aSKonstantin Belousov flags, cache, lockstate); 23227bd4146SNathan Whitehorn 23327bd4146SNathan Whitehorn if (def == NULL) 23427bd4146SNathan Whitehorn return (-1); 23527bd4146SNathan Whitehorn 23627bd4146SNathan Whitehorn /* 23727bd4146SNathan Whitehorn * We lazily allocate offsets for static TLS as we 23827bd4146SNathan Whitehorn * see the first relocation that references the 23927bd4146SNathan Whitehorn * TLS block. This allows us to support (small 24027bd4146SNathan Whitehorn * amounts of) static TLS in dynamically loaded 24127bd4146SNathan Whitehorn * modules. If we run out of space, we generate an 24227bd4146SNathan Whitehorn * error. 24327bd4146SNathan Whitehorn */ 24427bd4146SNathan Whitehorn if (!defobj->tls_done) { 24527bd4146SNathan Whitehorn if (!allocate_tls_offset((Obj_Entry*) defobj)) { 24627bd4146SNathan Whitehorn _rtld_error("%s: No space available for static " 24727bd4146SNathan Whitehorn "Thread Local Storage", obj->path); 24827bd4146SNathan Whitehorn return (-1); 24927bd4146SNathan Whitehorn } 25027bd4146SNathan Whitehorn } 25127bd4146SNathan Whitehorn 25227bd4146SNathan Whitehorn *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 25327bd4146SNathan Whitehorn + (Elf_Addr *)(def->st_value + rela->r_addend 25427bd4146SNathan Whitehorn + defobj->tlsoffset - TLS_TP_OFFSET); 25527bd4146SNathan Whitehorn 25627bd4146SNathan Whitehorn break; 25727bd4146SNathan Whitehorn 25827bd4146SNathan Whitehorn case R_PPC64_DTPREL64: 25927bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 260*082f959aSKonstantin Belousov flags, cache, lockstate); 26127bd4146SNathan Whitehorn 26227bd4146SNathan Whitehorn if (def == NULL) 26327bd4146SNathan Whitehorn return (-1); 26427bd4146SNathan Whitehorn 26527bd4146SNathan Whitehorn *where += (Elf_Addr)(def->st_value + rela->r_addend 26627bd4146SNathan Whitehorn - TLS_DTV_OFFSET); 26727bd4146SNathan Whitehorn 26827bd4146SNathan Whitehorn break; 26927bd4146SNathan Whitehorn 27027bd4146SNathan Whitehorn default: 27127bd4146SNathan Whitehorn _rtld_error("%s: Unsupported relocation type %ld" 27227bd4146SNathan Whitehorn " in non-PLT relocations\n", obj->path, 27327bd4146SNathan Whitehorn ELF_R_TYPE(rela->r_info)); 27427bd4146SNathan Whitehorn return (-1); 27527bd4146SNathan Whitehorn } 27627bd4146SNathan Whitehorn return (0); 27727bd4146SNathan Whitehorn } 27827bd4146SNathan Whitehorn 27927bd4146SNathan Whitehorn 28027bd4146SNathan Whitehorn /* 28127bd4146SNathan Whitehorn * Process non-PLT relocations 28227bd4146SNathan Whitehorn */ 28327bd4146SNathan Whitehorn int 284*082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 285*082f959aSKonstantin Belousov RtldLockState *lockstate) 28627bd4146SNathan Whitehorn { 28727bd4146SNathan Whitehorn const Elf_Rela *relalim; 28827bd4146SNathan Whitehorn const Elf_Rela *rela; 28927bd4146SNathan Whitehorn SymCache *cache; 29027bd4146SNathan Whitehorn int bytes = obj->nchains * sizeof(SymCache); 29127bd4146SNathan Whitehorn int r = -1; 29227bd4146SNathan Whitehorn 29327bd4146SNathan Whitehorn /* 29427bd4146SNathan Whitehorn * The dynamic loader may be called from a thread, we have 29527bd4146SNathan Whitehorn * limited amounts of stack available so we cannot use alloca(). 29627bd4146SNathan Whitehorn */ 29727bd4146SNathan Whitehorn if (obj != obj_rtld) { 29827bd4146SNathan Whitehorn cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 29927bd4146SNathan Whitehorn -1, 0); 30027bd4146SNathan Whitehorn if (cache == MAP_FAILED) 30127bd4146SNathan Whitehorn cache = NULL; 30227bd4146SNathan Whitehorn } else 30327bd4146SNathan Whitehorn cache = NULL; 30427bd4146SNathan Whitehorn 30527bd4146SNathan Whitehorn /* 30627bd4146SNathan Whitehorn * From the SVR4 PPC ABI: 30727bd4146SNathan Whitehorn * "The PowerPC family uses only the Elf32_Rela relocation 30827bd4146SNathan Whitehorn * entries with explicit addends." 30927bd4146SNathan Whitehorn */ 31027bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 31127bd4146SNathan Whitehorn for (rela = obj->rela; rela < relalim; rela++) { 312*082f959aSKonstantin Belousov if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, 313*082f959aSKonstantin Belousov lockstate) < 0) 31427bd4146SNathan Whitehorn goto done; 31527bd4146SNathan Whitehorn } 31627bd4146SNathan Whitehorn r = 0; 31727bd4146SNathan Whitehorn done: 3184b51c699SNathan Whitehorn if (cache) 31927bd4146SNathan Whitehorn munmap(cache, bytes); 3204b51c699SNathan Whitehorn 3214b51c699SNathan Whitehorn /* Synchronize icache for text seg in case we made any changes */ 3224b51c699SNathan Whitehorn __syncicache(obj->mapbase, obj->textsize); 3234b51c699SNathan Whitehorn 32427bd4146SNathan Whitehorn return (r); 32527bd4146SNathan Whitehorn } 32627bd4146SNathan Whitehorn 32727bd4146SNathan Whitehorn 32827bd4146SNathan Whitehorn /* 32927bd4146SNathan Whitehorn * Initialise a PLT slot to the resolving trampoline 33027bd4146SNathan Whitehorn */ 33127bd4146SNathan Whitehorn static int 33227bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 33327bd4146SNathan Whitehorn { 33427bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 33527bd4146SNathan Whitehorn Elf_Addr *glink; 33627bd4146SNathan Whitehorn long reloff; 33727bd4146SNathan Whitehorn 33827bd4146SNathan Whitehorn reloff = rela - obj->pltrela; 33927bd4146SNathan Whitehorn 34027bd4146SNathan Whitehorn if (obj->priv == NULL) 34127bd4146SNathan Whitehorn obj->priv = malloc(obj->pltrelasize); 34227bd4146SNathan Whitehorn glink = obj->priv + reloff*sizeof(Elf_Addr)*2; 34327bd4146SNathan Whitehorn 34427bd4146SNathan Whitehorn dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%p", (void *)where, reloff, glink); 34527bd4146SNathan Whitehorn 34627bd4146SNathan Whitehorn memcpy(where, _rtld_bind_start, sizeof(struct funcdesc)); 34727bd4146SNathan Whitehorn ((struct funcdesc *)(where))->env = (Elf_Addr)glink; 34827bd4146SNathan Whitehorn *(glink++) = (Elf_Addr)obj; 34927bd4146SNathan Whitehorn *(glink++) = reloff*sizeof(Elf_Rela); 35027bd4146SNathan Whitehorn 35127bd4146SNathan Whitehorn return (0); 35227bd4146SNathan Whitehorn } 35327bd4146SNathan Whitehorn 35427bd4146SNathan Whitehorn 35527bd4146SNathan Whitehorn /* 35627bd4146SNathan Whitehorn * Process the PLT relocations. 35727bd4146SNathan Whitehorn */ 35827bd4146SNathan Whitehorn int 35927bd4146SNathan Whitehorn reloc_plt(Obj_Entry *obj) 36027bd4146SNathan Whitehorn { 36127bd4146SNathan Whitehorn const Elf_Rela *relalim; 36227bd4146SNathan Whitehorn const Elf_Rela *rela; 36327bd4146SNathan Whitehorn 36427bd4146SNathan Whitehorn if (obj->pltrelasize != 0) { 36527bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((char *)obj->pltrela + 36627bd4146SNathan Whitehorn obj->pltrelasize); 36727bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 36827bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 36927bd4146SNathan Whitehorn 37027bd4146SNathan Whitehorn if (reloc_plt_object(obj, rela) < 0) { 37127bd4146SNathan Whitehorn return (-1); 37227bd4146SNathan Whitehorn } 37327bd4146SNathan Whitehorn } 37427bd4146SNathan Whitehorn } 37527bd4146SNathan Whitehorn 37627bd4146SNathan Whitehorn return (0); 37727bd4146SNathan Whitehorn } 37827bd4146SNathan Whitehorn 37927bd4146SNathan Whitehorn 38027bd4146SNathan Whitehorn /* 38127bd4146SNathan Whitehorn * LD_BIND_NOW was set - force relocation for all jump slots 38227bd4146SNathan Whitehorn */ 38327bd4146SNathan Whitehorn int 384*082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 38527bd4146SNathan Whitehorn { 38627bd4146SNathan Whitehorn const Obj_Entry *defobj; 38727bd4146SNathan Whitehorn const Elf_Rela *relalim; 38827bd4146SNathan Whitehorn const Elf_Rela *rela; 38927bd4146SNathan Whitehorn const Elf_Sym *def; 39027bd4146SNathan Whitehorn Elf_Addr *where; 39127bd4146SNathan Whitehorn Elf_Addr target; 39227bd4146SNathan Whitehorn 39327bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 39427bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 39527bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 39627bd4146SNathan Whitehorn where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 39727bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 398*082f959aSKonstantin Belousov SYMLOOK_IN_PLT | flags, NULL, lockstate); 39927bd4146SNathan Whitehorn if (def == NULL) { 40027bd4146SNathan Whitehorn dbg("reloc_jmpslots: sym not found"); 40127bd4146SNathan Whitehorn return (-1); 40227bd4146SNathan Whitehorn } 40327bd4146SNathan Whitehorn 40427bd4146SNathan Whitehorn target = (Elf_Addr)(defobj->relocbase + def->st_value); 40527bd4146SNathan Whitehorn 40627bd4146SNathan Whitehorn #if 0 40727bd4146SNathan Whitehorn /* PG XXX */ 40827bd4146SNathan Whitehorn dbg("\"%s\" in \"%s\" --> %p in \"%s\"", 40927bd4146SNathan Whitehorn defobj->strtab + def->st_name, basename(obj->path), 41027bd4146SNathan Whitehorn (void *)target, basename(defobj->path)); 41127bd4146SNathan Whitehorn #endif 41227bd4146SNathan Whitehorn 413d48dde6fSNathan Whitehorn if (def == &sym_zero) { 414d48dde6fSNathan Whitehorn /* Zero undefined weak symbols */ 415d48dde6fSNathan Whitehorn bzero(where, sizeof(struct funcdesc)); 416d48dde6fSNathan Whitehorn } else { 41727bd4146SNathan Whitehorn reloc_jmpslot(where, target, defobj, obj, 41827bd4146SNathan Whitehorn (const Elf_Rel *) rela); 41927bd4146SNathan Whitehorn } 420d48dde6fSNathan Whitehorn } 42127bd4146SNathan Whitehorn 42227bd4146SNathan Whitehorn obj->jmpslots_done = true; 42327bd4146SNathan Whitehorn 42427bd4146SNathan Whitehorn return (0); 42527bd4146SNathan Whitehorn } 42627bd4146SNathan Whitehorn 42727bd4146SNathan Whitehorn 42827bd4146SNathan Whitehorn /* 42927bd4146SNathan Whitehorn * Update the value of a PLT jump slot. 43027bd4146SNathan Whitehorn */ 43127bd4146SNathan Whitehorn Elf_Addr 43227bd4146SNathan Whitehorn reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, 43327bd4146SNathan Whitehorn const Obj_Entry *obj, const Elf_Rel *rel) 43427bd4146SNathan Whitehorn { 43527bd4146SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", 43627bd4146SNathan Whitehorn (void *)wherep, (void *)target, *(Elf_Addr *)target, 43727bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase); 43827bd4146SNathan Whitehorn 43927bd4146SNathan Whitehorn /* 44027bd4146SNathan Whitehorn * At the PLT entry pointed at by `wherep', construct 44127bd4146SNathan Whitehorn * a direct transfer to the now fully resolved function 44227bd4146SNathan Whitehorn * address. 44327bd4146SNathan Whitehorn */ 44427bd4146SNathan Whitehorn 44527bd4146SNathan Whitehorn memcpy(wherep, (void *)target, sizeof(struct funcdesc)); 44627bd4146SNathan Whitehorn if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { 44727bd4146SNathan Whitehorn /* 44827bd4146SNathan Whitehorn * XXX: It is possible (e.g. LD_BIND_NOW) that the function 44927bd4146SNathan Whitehorn * descriptor we are copying has not yet been relocated. 45027bd4146SNathan Whitehorn * If this happens, fix it. 45127bd4146SNathan Whitehorn */ 45227bd4146SNathan Whitehorn 45327bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->addr += 45427bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 45527bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->toc += 45627bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 45727bd4146SNathan Whitehorn } 45827bd4146SNathan Whitehorn 45927bd4146SNathan Whitehorn __asm __volatile("dcbst 0,%0; sync" :: "r"(wherep) : "memory"); 46027bd4146SNathan Whitehorn 46127bd4146SNathan Whitehorn return (target); 46227bd4146SNathan Whitehorn } 46327bd4146SNathan Whitehorn 4646be4b697SKonstantin Belousov int 4656be4b697SKonstantin Belousov reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 4666be4b697SKonstantin Belousov { 4676be4b697SKonstantin Belousov 4686be4b697SKonstantin Belousov /* XXX not implemented */ 4696be4b697SKonstantin Belousov return (0); 4706be4b697SKonstantin Belousov } 4716be4b697SKonstantin Belousov 4726be4b697SKonstantin Belousov int 473*082f959aSKonstantin Belousov reloc_gnu_ifunc(Obj_Entry *obj, int flags, 474*082f959aSKonstantin Belousov struct Struct_RtldLockState *lockstate) 4756be4b697SKonstantin Belousov { 4766be4b697SKonstantin Belousov 4776be4b697SKonstantin Belousov /* XXX not implemented */ 4786be4b697SKonstantin Belousov return (0); 4796be4b697SKonstantin Belousov } 4806be4b697SKonstantin Belousov 48127bd4146SNathan Whitehorn void 48227bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj) 48327bd4146SNathan Whitehorn { 48427bd4146SNathan Whitehorn } 48527bd4146SNathan Whitehorn 48627bd4146SNathan Whitehorn void 48727bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list) 48827bd4146SNathan Whitehorn { 48927bd4146SNathan Whitehorn register Elf_Addr **tp __asm__("r13"); 49027bd4146SNathan Whitehorn Elf_Addr **_tp; 49127bd4146SNathan Whitehorn 49227bd4146SNathan Whitehorn /* 49327bd4146SNathan Whitehorn * Fix the size of the static TLS block by using the maximum 49427bd4146SNathan Whitehorn * offset allocated so far and adding a bit for dynamic modules to 49527bd4146SNathan Whitehorn * use. 49627bd4146SNathan Whitehorn */ 49727bd4146SNathan Whitehorn 49827bd4146SNathan Whitehorn tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 49927bd4146SNathan Whitehorn 50027bd4146SNathan Whitehorn _tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16) 50127bd4146SNathan Whitehorn + TLS_TP_OFFSET + TLS_TCB_SIZE); 50227bd4146SNathan Whitehorn 50327bd4146SNathan Whitehorn /* 50427bd4146SNathan Whitehorn * XXX gcc seems to ignore 'tp = _tp;' 50527bd4146SNathan Whitehorn */ 50627bd4146SNathan Whitehorn 50727bd4146SNathan Whitehorn __asm __volatile("mr %0,%1" : "=r"(tp) : "r"(_tp)); 50827bd4146SNathan Whitehorn } 50927bd4146SNathan Whitehorn 51027bd4146SNathan Whitehorn void* 51127bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti) 51227bd4146SNathan Whitehorn { 51327bd4146SNathan Whitehorn register Elf_Addr **tp __asm__("r13"); 51427bd4146SNathan Whitehorn char *p; 51527bd4146SNathan Whitehorn 51627bd4146SNathan Whitehorn p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 51727bd4146SNathan Whitehorn - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); 51827bd4146SNathan Whitehorn 51927bd4146SNathan Whitehorn return (p + TLS_DTV_OFFSET); 52027bd4146SNathan Whitehorn } 521