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> 40a29cc9a3SAndriy Gapon #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 4629ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 4727bd4146SNathan Whitehorn struct funcdesc { 4827bd4146SNathan Whitehorn Elf_Addr addr; 4927bd4146SNathan Whitehorn Elf_Addr toc; 5027bd4146SNathan Whitehorn Elf_Addr env; 5127bd4146SNathan Whitehorn }; 5229ba9b61SNathan Whitehorn #endif 5327bd4146SNathan Whitehorn 5427bd4146SNathan Whitehorn /* 5527bd4146SNathan Whitehorn * Process the R_PPC_COPY relocations 5627bd4146SNathan Whitehorn */ 5727bd4146SNathan Whitehorn int 5827bd4146SNathan Whitehorn do_copy_relocations(Obj_Entry *dstobj) 5927bd4146SNathan Whitehorn { 6027bd4146SNathan Whitehorn const Elf_Rela *relalim; 6127bd4146SNathan Whitehorn const Elf_Rela *rela; 6227bd4146SNathan Whitehorn 6327bd4146SNathan Whitehorn /* 6427bd4146SNathan Whitehorn * COPY relocs are invalid outside of the main program 6527bd4146SNathan Whitehorn */ 6627bd4146SNathan Whitehorn assert(dstobj->mainprog); 6727bd4146SNathan Whitehorn 6827bd4146SNathan Whitehorn relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + 6927bd4146SNathan Whitehorn dstobj->relasize); 7027bd4146SNathan Whitehorn for (rela = dstobj->rela; rela < relalim; rela++) { 7127bd4146SNathan Whitehorn void *dstaddr; 7227bd4146SNathan Whitehorn const Elf_Sym *dstsym; 7327bd4146SNathan Whitehorn const char *name; 7427bd4146SNathan Whitehorn size_t size; 7527bd4146SNathan Whitehorn const void *srcaddr; 7627bd4146SNathan Whitehorn const Elf_Sym *srcsym = NULL; 778569deafSKonstantin Belousov const Obj_Entry *srcobj, *defobj; 788569deafSKonstantin Belousov SymLook req; 798569deafSKonstantin Belousov int res; 8027bd4146SNathan Whitehorn 8127bd4146SNathan Whitehorn if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 8227bd4146SNathan Whitehorn continue; 8327bd4146SNathan Whitehorn } 8427bd4146SNathan Whitehorn 8527bd4146SNathan Whitehorn dstaddr = (void *) (dstobj->relocbase + rela->r_offset); 8627bd4146SNathan Whitehorn dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 8727bd4146SNathan Whitehorn name = dstobj->strtab + dstsym->st_name; 8827bd4146SNathan Whitehorn size = dstsym->st_size; 898569deafSKonstantin Belousov symlook_init(&req, name); 908569deafSKonstantin Belousov req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 91082f959aSKonstantin Belousov req.flags = SYMLOOK_EARLY; 9227bd4146SNathan Whitehorn 93*9fee0541SKonstantin Belousov for (srcobj = globallist_next(dstobj); srcobj != NULL; 94*9fee0541SKonstantin Belousov srcobj = globallist_next(srcobj)) { 958569deafSKonstantin Belousov res = symlook_obj(&req, srcobj); 968569deafSKonstantin Belousov if (res == 0) { 978569deafSKonstantin Belousov srcsym = req.sym_out; 988569deafSKonstantin Belousov defobj = req.defobj_out; 9927bd4146SNathan Whitehorn break; 10027bd4146SNathan Whitehorn } 10127bd4146SNathan Whitehorn } 10227bd4146SNathan Whitehorn 10327bd4146SNathan Whitehorn if (srcobj == NULL) { 10427bd4146SNathan Whitehorn _rtld_error("Undefined symbol \"%s\" " 10527bd4146SNathan Whitehorn " referenced from COPY" 10627bd4146SNathan Whitehorn " relocation in %s", name, dstobj->path); 10727bd4146SNathan Whitehorn return (-1); 10827bd4146SNathan Whitehorn } 10927bd4146SNathan Whitehorn 1108569deafSKonstantin Belousov srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); 11127bd4146SNathan Whitehorn memcpy(dstaddr, srcaddr, size); 11227bd4146SNathan Whitehorn dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); 11327bd4146SNathan Whitehorn } 11427bd4146SNathan Whitehorn 11527bd4146SNathan Whitehorn return (0); 11627bd4146SNathan Whitehorn } 11727bd4146SNathan Whitehorn 11827bd4146SNathan Whitehorn 11927bd4146SNathan Whitehorn /* 12027bd4146SNathan Whitehorn * Perform early relocation of the run-time linker image 12127bd4146SNathan Whitehorn */ 12227bd4146SNathan Whitehorn void 12327bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 12427bd4146SNathan Whitehorn { 12527bd4146SNathan Whitehorn const Elf_Rela *rela = 0, *relalim; 12627bd4146SNathan Whitehorn Elf_Addr relasz = 0; 12727bd4146SNathan Whitehorn Elf_Addr *where; 12827bd4146SNathan Whitehorn 12927bd4146SNathan Whitehorn /* 13027bd4146SNathan Whitehorn * Extract the rela/relasz values from the dynamic section 13127bd4146SNathan Whitehorn */ 13227bd4146SNathan Whitehorn for (; dynp->d_tag != DT_NULL; dynp++) { 13327bd4146SNathan Whitehorn switch (dynp->d_tag) { 13427bd4146SNathan Whitehorn case DT_RELA: 13527bd4146SNathan Whitehorn rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 13627bd4146SNathan Whitehorn break; 13727bd4146SNathan Whitehorn case DT_RELASZ: 13827bd4146SNathan Whitehorn relasz = dynp->d_un.d_val; 13927bd4146SNathan Whitehorn break; 14027bd4146SNathan Whitehorn } 14127bd4146SNathan Whitehorn } 14227bd4146SNathan Whitehorn 14327bd4146SNathan Whitehorn /* 14427bd4146SNathan Whitehorn * Relocate these values 14527bd4146SNathan Whitehorn */ 14627bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 14727bd4146SNathan Whitehorn for (; rela < relalim; rela++) { 14827bd4146SNathan Whitehorn where = (Elf_Addr *)(relocbase + rela->r_offset); 14927bd4146SNathan Whitehorn *where = (Elf_Addr)(relocbase + rela->r_addend); 15027bd4146SNathan Whitehorn } 15127bd4146SNathan Whitehorn } 15227bd4146SNathan Whitehorn 15327bd4146SNathan Whitehorn 15427bd4146SNathan Whitehorn /* 15527bd4146SNathan Whitehorn * Relocate a non-PLT object with addend. 15627bd4146SNathan Whitehorn */ 15727bd4146SNathan Whitehorn static int 15827bd4146SNathan Whitehorn reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 159082f959aSKonstantin Belousov SymCache *cache, int flags, RtldLockState *lockstate) 16027bd4146SNathan Whitehorn { 16127bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 16227bd4146SNathan Whitehorn const Elf_Sym *def; 16327bd4146SNathan Whitehorn const Obj_Entry *defobj; 16427bd4146SNathan Whitehorn Elf_Addr tmp; 16527bd4146SNathan Whitehorn 16627bd4146SNathan Whitehorn switch (ELF_R_TYPE(rela->r_info)) { 16727bd4146SNathan Whitehorn 16827bd4146SNathan Whitehorn case R_PPC_NONE: 16927bd4146SNathan Whitehorn break; 17027bd4146SNathan Whitehorn 1719cc92083SNathan Whitehorn case R_PPC64_UADDR64: /* doubleword64 S + A */ 1729cc92083SNathan Whitehorn case R_PPC64_ADDR64: 17327bd4146SNathan Whitehorn case R_PPC_GLOB_DAT: 17427bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 175082f959aSKonstantin Belousov flags, cache, lockstate); 17627bd4146SNathan Whitehorn if (def == NULL) { 17727bd4146SNathan Whitehorn return (-1); 17827bd4146SNathan Whitehorn } 17927bd4146SNathan Whitehorn 18027bd4146SNathan Whitehorn tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 18127bd4146SNathan Whitehorn rela->r_addend); 18227bd4146SNathan Whitehorn 18327bd4146SNathan Whitehorn /* Don't issue write if unnecessary; avoid COW page fault */ 18427bd4146SNathan Whitehorn if (*where != tmp) { 18527bd4146SNathan Whitehorn *where = tmp; 18627bd4146SNathan Whitehorn } 18727bd4146SNathan Whitehorn break; 18827bd4146SNathan Whitehorn 18927bd4146SNathan Whitehorn case R_PPC_RELATIVE: /* doubleword64 B + A */ 19027bd4146SNathan Whitehorn tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 19127bd4146SNathan Whitehorn 19227bd4146SNathan Whitehorn /* As above, don't issue write unnecessarily */ 19327bd4146SNathan Whitehorn if (*where != tmp) { 19427bd4146SNathan Whitehorn *where = tmp; 19527bd4146SNathan Whitehorn } 19627bd4146SNathan Whitehorn break; 19727bd4146SNathan Whitehorn 19827bd4146SNathan Whitehorn case R_PPC_COPY: 19927bd4146SNathan Whitehorn /* 20027bd4146SNathan Whitehorn * These are deferred until all other relocations 20127bd4146SNathan Whitehorn * have been done. All we do here is make sure 20227bd4146SNathan Whitehorn * that the COPY relocation is not in a shared 20327bd4146SNathan Whitehorn * library. They are allowed only in executable 20427bd4146SNathan Whitehorn * files. 20527bd4146SNathan Whitehorn */ 20627bd4146SNathan Whitehorn if (!obj->mainprog) { 20727bd4146SNathan Whitehorn _rtld_error("%s: Unexpected R_COPY " 20827bd4146SNathan Whitehorn " relocation in shared library", 20927bd4146SNathan Whitehorn obj->path); 21027bd4146SNathan Whitehorn return (-1); 21127bd4146SNathan Whitehorn } 21227bd4146SNathan Whitehorn break; 21327bd4146SNathan Whitehorn 21427bd4146SNathan Whitehorn case R_PPC_JMP_SLOT: 21527bd4146SNathan Whitehorn /* 21627bd4146SNathan Whitehorn * These will be handled by the plt/jmpslot routines 21727bd4146SNathan Whitehorn */ 21827bd4146SNathan Whitehorn break; 21927bd4146SNathan Whitehorn 22027bd4146SNathan Whitehorn case R_PPC64_DTPMOD64: 22127bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 222082f959aSKonstantin Belousov flags, cache, lockstate); 22327bd4146SNathan Whitehorn 22427bd4146SNathan Whitehorn if (def == NULL) 22527bd4146SNathan Whitehorn return (-1); 22627bd4146SNathan Whitehorn 22727bd4146SNathan Whitehorn *where = (Elf_Addr) defobj->tlsindex; 22827bd4146SNathan Whitehorn 22927bd4146SNathan Whitehorn break; 23027bd4146SNathan Whitehorn 23127bd4146SNathan Whitehorn case R_PPC64_TPREL64: 23227bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 233082f959aSKonstantin Belousov flags, cache, lockstate); 23427bd4146SNathan Whitehorn 23527bd4146SNathan Whitehorn if (def == NULL) 23627bd4146SNathan Whitehorn return (-1); 23727bd4146SNathan Whitehorn 23827bd4146SNathan Whitehorn /* 23927bd4146SNathan Whitehorn * We lazily allocate offsets for static TLS as we 24027bd4146SNathan Whitehorn * see the first relocation that references the 24127bd4146SNathan Whitehorn * TLS block. This allows us to support (small 24227bd4146SNathan Whitehorn * amounts of) static TLS in dynamically loaded 24327bd4146SNathan Whitehorn * modules. If we run out of space, we generate an 24427bd4146SNathan Whitehorn * error. 24527bd4146SNathan Whitehorn */ 24627bd4146SNathan Whitehorn if (!defobj->tls_done) { 24727bd4146SNathan Whitehorn if (!allocate_tls_offset((Obj_Entry*) defobj)) { 24827bd4146SNathan Whitehorn _rtld_error("%s: No space available for static " 24927bd4146SNathan Whitehorn "Thread Local Storage", obj->path); 25027bd4146SNathan Whitehorn return (-1); 25127bd4146SNathan Whitehorn } 25227bd4146SNathan Whitehorn } 25327bd4146SNathan Whitehorn 25427bd4146SNathan Whitehorn *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 25527bd4146SNathan Whitehorn + (Elf_Addr *)(def->st_value + rela->r_addend 25627bd4146SNathan Whitehorn + defobj->tlsoffset - TLS_TP_OFFSET); 25727bd4146SNathan Whitehorn 25827bd4146SNathan Whitehorn break; 25927bd4146SNathan Whitehorn 26027bd4146SNathan Whitehorn case R_PPC64_DTPREL64: 26127bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 262082f959aSKonstantin Belousov flags, cache, lockstate); 26327bd4146SNathan Whitehorn 26427bd4146SNathan Whitehorn if (def == NULL) 26527bd4146SNathan Whitehorn return (-1); 26627bd4146SNathan Whitehorn 26727bd4146SNathan Whitehorn *where += (Elf_Addr)(def->st_value + rela->r_addend 26827bd4146SNathan Whitehorn - TLS_DTV_OFFSET); 26927bd4146SNathan Whitehorn 27027bd4146SNathan Whitehorn break; 27127bd4146SNathan Whitehorn 27227bd4146SNathan Whitehorn default: 27327bd4146SNathan Whitehorn _rtld_error("%s: Unsupported relocation type %ld" 27427bd4146SNathan Whitehorn " in non-PLT relocations\n", obj->path, 27527bd4146SNathan Whitehorn ELF_R_TYPE(rela->r_info)); 27627bd4146SNathan Whitehorn return (-1); 27727bd4146SNathan Whitehorn } 27827bd4146SNathan Whitehorn return (0); 27927bd4146SNathan Whitehorn } 28027bd4146SNathan Whitehorn 28127bd4146SNathan Whitehorn 28227bd4146SNathan Whitehorn /* 28327bd4146SNathan Whitehorn * Process non-PLT relocations 28427bd4146SNathan Whitehorn */ 28527bd4146SNathan Whitehorn int 286082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 287082f959aSKonstantin Belousov RtldLockState *lockstate) 28827bd4146SNathan Whitehorn { 28927bd4146SNathan Whitehorn const Elf_Rela *relalim; 29027bd4146SNathan Whitehorn const Elf_Rela *rela; 29127bd4146SNathan Whitehorn SymCache *cache; 292f6265192SKonstantin Belousov int bytes = obj->dynsymcount * sizeof(SymCache); 29327bd4146SNathan Whitehorn int r = -1; 29427bd4146SNathan Whitehorn 29514c35647SKonstantin Belousov if ((flags & SYMLOOK_IFUNC) != 0) 29614c35647SKonstantin Belousov /* XXX not implemented */ 29714c35647SKonstantin Belousov return (0); 29814c35647SKonstantin Belousov 29927bd4146SNathan Whitehorn /* 30027bd4146SNathan Whitehorn * The dynamic loader may be called from a thread, we have 30127bd4146SNathan Whitehorn * limited amounts of stack available so we cannot use alloca(). 30227bd4146SNathan Whitehorn */ 30327bd4146SNathan Whitehorn if (obj != obj_rtld) { 30427bd4146SNathan Whitehorn cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 30527bd4146SNathan Whitehorn -1, 0); 30627bd4146SNathan Whitehorn if (cache == MAP_FAILED) 30727bd4146SNathan Whitehorn cache = NULL; 30827bd4146SNathan Whitehorn } else 30927bd4146SNathan Whitehorn cache = NULL; 31027bd4146SNathan Whitehorn 31127bd4146SNathan Whitehorn /* 31227bd4146SNathan Whitehorn * From the SVR4 PPC ABI: 31327bd4146SNathan Whitehorn * "The PowerPC family uses only the Elf32_Rela relocation 31427bd4146SNathan Whitehorn * entries with explicit addends." 31527bd4146SNathan Whitehorn */ 31627bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 31727bd4146SNathan Whitehorn for (rela = obj->rela; rela < relalim; rela++) { 318082f959aSKonstantin Belousov if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, 319082f959aSKonstantin Belousov lockstate) < 0) 32027bd4146SNathan Whitehorn goto done; 32127bd4146SNathan Whitehorn } 32227bd4146SNathan Whitehorn r = 0; 32327bd4146SNathan Whitehorn done: 3244b51c699SNathan Whitehorn if (cache) 32527bd4146SNathan Whitehorn munmap(cache, bytes); 3264b51c699SNathan Whitehorn 3274b51c699SNathan Whitehorn /* Synchronize icache for text seg in case we made any changes */ 3284b51c699SNathan Whitehorn __syncicache(obj->mapbase, obj->textsize); 3294b51c699SNathan Whitehorn 33027bd4146SNathan Whitehorn return (r); 33127bd4146SNathan Whitehorn } 33227bd4146SNathan Whitehorn 33327bd4146SNathan Whitehorn 33427bd4146SNathan Whitehorn /* 33527bd4146SNathan Whitehorn * Initialise a PLT slot to the resolving trampoline 33627bd4146SNathan Whitehorn */ 33727bd4146SNathan Whitehorn static int 33827bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 33927bd4146SNathan Whitehorn { 34027bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 34127bd4146SNathan Whitehorn long reloff; 34227bd4146SNathan Whitehorn 34327bd4146SNathan Whitehorn reloff = rela - obj->pltrela; 34427bd4146SNathan Whitehorn 345a4c5dfc0SNathan Whitehorn dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, 346a4c5dfc0SNathan Whitehorn reloff, obj->glink); 347a4c5dfc0SNathan Whitehorn 34829ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 349a4c5dfc0SNathan Whitehorn /* Glink code is 3 instructions after the first 32k, 2 before */ 350a4c5dfc0SNathan Whitehorn *where = (Elf_Addr)obj->glink + 32 + 351a4c5dfc0SNathan Whitehorn 8*((reloff < 0x8000) ? reloff : 0x8000) + 352a4c5dfc0SNathan Whitehorn 12*((reloff < 0x8000) ? 0 : (reloff - 0x8000)); 35329ba9b61SNathan Whitehorn #else 35429ba9b61SNathan Whitehorn *where = (Elf_Addr)obj->glink + 4*reloff + 32; 35529ba9b61SNathan Whitehorn #endif 35627bd4146SNathan Whitehorn 35727bd4146SNathan Whitehorn return (0); 35827bd4146SNathan Whitehorn } 35927bd4146SNathan Whitehorn 36027bd4146SNathan Whitehorn 36127bd4146SNathan Whitehorn /* 36227bd4146SNathan Whitehorn * Process the PLT relocations. 36327bd4146SNathan Whitehorn */ 36427bd4146SNathan Whitehorn int 36527bd4146SNathan Whitehorn reloc_plt(Obj_Entry *obj) 36627bd4146SNathan Whitehorn { 36727bd4146SNathan Whitehorn const Elf_Rela *relalim; 36827bd4146SNathan Whitehorn const Elf_Rela *rela; 36927bd4146SNathan Whitehorn 37027bd4146SNathan Whitehorn if (obj->pltrelasize != 0) { 37127bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((char *)obj->pltrela + 37227bd4146SNathan Whitehorn obj->pltrelasize); 37327bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 37427bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 37527bd4146SNathan Whitehorn 37627bd4146SNathan Whitehorn if (reloc_plt_object(obj, rela) < 0) { 37727bd4146SNathan Whitehorn return (-1); 37827bd4146SNathan Whitehorn } 37927bd4146SNathan Whitehorn } 38027bd4146SNathan Whitehorn } 38127bd4146SNathan Whitehorn 38227bd4146SNathan Whitehorn return (0); 38327bd4146SNathan Whitehorn } 38427bd4146SNathan Whitehorn 38527bd4146SNathan Whitehorn 38627bd4146SNathan Whitehorn /* 38727bd4146SNathan Whitehorn * LD_BIND_NOW was set - force relocation for all jump slots 38827bd4146SNathan Whitehorn */ 38927bd4146SNathan Whitehorn int 390082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 39127bd4146SNathan Whitehorn { 39227bd4146SNathan Whitehorn const Obj_Entry *defobj; 39327bd4146SNathan Whitehorn const Elf_Rela *relalim; 39427bd4146SNathan Whitehorn const Elf_Rela *rela; 39527bd4146SNathan Whitehorn const Elf_Sym *def; 39627bd4146SNathan Whitehorn Elf_Addr *where; 39727bd4146SNathan Whitehorn Elf_Addr target; 39827bd4146SNathan Whitehorn 39927bd4146SNathan Whitehorn relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 40027bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) { 40127bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 40227bd4146SNathan Whitehorn where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 40327bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 404082f959aSKonstantin Belousov SYMLOOK_IN_PLT | flags, NULL, lockstate); 40527bd4146SNathan Whitehorn if (def == NULL) { 40627bd4146SNathan Whitehorn dbg("reloc_jmpslots: sym not found"); 40727bd4146SNathan Whitehorn return (-1); 40827bd4146SNathan Whitehorn } 40927bd4146SNathan Whitehorn 41027bd4146SNathan Whitehorn target = (Elf_Addr)(defobj->relocbase + def->st_value); 41127bd4146SNathan Whitehorn 412d48dde6fSNathan Whitehorn if (def == &sym_zero) { 413d48dde6fSNathan Whitehorn /* Zero undefined weak symbols */ 41429ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 415d48dde6fSNathan Whitehorn bzero(where, sizeof(struct funcdesc)); 41629ba9b61SNathan Whitehorn #else 41729ba9b61SNathan Whitehorn *where = 0; 41829ba9b61SNathan Whitehorn #endif 419d48dde6fSNathan Whitehorn } else { 42027bd4146SNathan Whitehorn reloc_jmpslot(where, target, defobj, obj, 42127bd4146SNathan Whitehorn (const Elf_Rel *) rela); 42227bd4146SNathan Whitehorn } 423d48dde6fSNathan Whitehorn } 42427bd4146SNathan Whitehorn 42527bd4146SNathan Whitehorn obj->jmpslots_done = true; 42627bd4146SNathan Whitehorn 42727bd4146SNathan Whitehorn return (0); 42827bd4146SNathan Whitehorn } 42927bd4146SNathan Whitehorn 43027bd4146SNathan Whitehorn 43127bd4146SNathan Whitehorn /* 43227bd4146SNathan Whitehorn * Update the value of a PLT jump slot. 43327bd4146SNathan Whitehorn */ 43427bd4146SNathan Whitehorn Elf_Addr 43527bd4146SNathan Whitehorn reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, 43627bd4146SNathan Whitehorn const Obj_Entry *obj, const Elf_Rel *rel) 43727bd4146SNathan Whitehorn { 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 44529ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1 44629ba9b61SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", 44729ba9b61SNathan Whitehorn (void *)wherep, (void *)target, *(Elf_Addr *)target, 44829ba9b61SNathan Whitehorn (Elf_Addr)defobj->relocbase); 44929ba9b61SNathan Whitehorn 450a4c5dfc0SNathan Whitehorn /* 451a4c5dfc0SNathan Whitehorn * For the trampoline, the second two elements of the function 452a4c5dfc0SNathan Whitehorn * descriptor are unused, so we are fine replacing those at any time 453a4c5dfc0SNathan Whitehorn * with the real ones with no thread safety implications. However, we 454a4c5dfc0SNathan Whitehorn * need to make sure the main entry point pointer ([0]) is seen to be 455a4c5dfc0SNathan Whitehorn * modified *after* the second two elements. This can't be done in 456a4c5dfc0SNathan Whitehorn * general, since there are no barriers in the reading code, but put in 457a4c5dfc0SNathan Whitehorn * some isyncs to at least make it a little better. 458a4c5dfc0SNathan Whitehorn */ 45927bd4146SNathan Whitehorn memcpy(wherep, (void *)target, sizeof(struct funcdesc)); 460a4c5dfc0SNathan Whitehorn wherep[2] = ((Elf_Addr *)target)[2]; 461a4c5dfc0SNathan Whitehorn wherep[1] = ((Elf_Addr *)target)[1]; 462a4c5dfc0SNathan Whitehorn __asm __volatile ("isync" : : : "memory"); 463a4c5dfc0SNathan Whitehorn wherep[0] = ((Elf_Addr *)target)[0]; 464a4c5dfc0SNathan Whitehorn __asm __volatile ("isync" : : : "memory"); 465a4c5dfc0SNathan Whitehorn 46627bd4146SNathan Whitehorn if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { 46727bd4146SNathan Whitehorn /* 468a4c5dfc0SNathan Whitehorn * It is possible (LD_BIND_NOW) that the function 46927bd4146SNathan Whitehorn * descriptor we are copying has not yet been relocated. 470a4c5dfc0SNathan Whitehorn * If this happens, fix it. Don't worry about threading in 471a4c5dfc0SNathan Whitehorn * this case since LD_BIND_NOW makes it irrelevant. 47227bd4146SNathan Whitehorn */ 47327bd4146SNathan Whitehorn 47427bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->addr += 47527bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 47627bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->toc += 47727bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase; 47827bd4146SNathan Whitehorn } 47929ba9b61SNathan Whitehorn #else 48029ba9b61SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, 48129ba9b61SNathan Whitehorn (void *)target); 48227bd4146SNathan Whitehorn 48329ba9b61SNathan Whitehorn *wherep = target; 48429ba9b61SNathan Whitehorn #endif 48529ba9b61SNathan Whitehorn 48627bd4146SNathan Whitehorn return (target); 48727bd4146SNathan Whitehorn } 48827bd4146SNathan Whitehorn 4896be4b697SKonstantin Belousov int 4906be4b697SKonstantin Belousov reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 4916be4b697SKonstantin Belousov { 4926be4b697SKonstantin Belousov 4936be4b697SKonstantin Belousov /* XXX not implemented */ 4946be4b697SKonstantin Belousov return (0); 4956be4b697SKonstantin Belousov } 4966be4b697SKonstantin Belousov 4976be4b697SKonstantin Belousov int 498082f959aSKonstantin Belousov reloc_gnu_ifunc(Obj_Entry *obj, int flags, 499082f959aSKonstantin Belousov struct Struct_RtldLockState *lockstate) 5006be4b697SKonstantin Belousov { 5016be4b697SKonstantin Belousov 5026be4b697SKonstantin Belousov /* XXX not implemented */ 5036be4b697SKonstantin Belousov return (0); 5046be4b697SKonstantin Belousov } 5056be4b697SKonstantin Belousov 50627bd4146SNathan Whitehorn void 50727bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj) 50827bd4146SNathan Whitehorn { 50929ba9b61SNathan Whitehorn Elf_Addr *pltcall; 51029ba9b61SNathan Whitehorn 51129ba9b61SNathan Whitehorn pltcall = obj->pltgot; 51229ba9b61SNathan Whitehorn 51329ba9b61SNathan Whitehorn if (pltcall == NULL) { 51429ba9b61SNathan Whitehorn return; 51529ba9b61SNathan Whitehorn } 51629ba9b61SNathan Whitehorn 517a4c5dfc0SNathan Whitehorn #if defined(_CALL_ELF) && _CALL_ELF == 2 51829ba9b61SNathan Whitehorn pltcall[0] = (Elf_Addr)&_rtld_bind_start; 51929ba9b61SNathan Whitehorn pltcall[1] = (Elf_Addr)obj; 520a4c5dfc0SNathan Whitehorn #else 521a4c5dfc0SNathan Whitehorn memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc)); 522a4c5dfc0SNathan Whitehorn pltcall[2] = (Elf_Addr)obj; 52329ba9b61SNathan Whitehorn #endif 52427bd4146SNathan Whitehorn } 52527bd4146SNathan Whitehorn 52627bd4146SNathan Whitehorn void 52727bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list) 52827bd4146SNathan Whitehorn { 529746ae9dfSNathan Whitehorn Elf_Addr **tp; 53027bd4146SNathan Whitehorn 53127bd4146SNathan Whitehorn /* 53227bd4146SNathan Whitehorn * Fix the size of the static TLS block by using the maximum 53327bd4146SNathan Whitehorn * offset allocated so far and adding a bit for dynamic modules to 53427bd4146SNathan Whitehorn * use. 53527bd4146SNathan Whitehorn */ 53627bd4146SNathan Whitehorn 53727bd4146SNathan Whitehorn tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 53827bd4146SNathan Whitehorn 539746ae9dfSNathan Whitehorn tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16) 54027bd4146SNathan Whitehorn + TLS_TP_OFFSET + TLS_TCB_SIZE); 54127bd4146SNathan Whitehorn 542746ae9dfSNathan Whitehorn __asm __volatile("mr 13,%0" :: "r"(tp)); 54327bd4146SNathan Whitehorn } 54427bd4146SNathan Whitehorn 54527bd4146SNathan Whitehorn void* 54627bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti) 54727bd4146SNathan Whitehorn { 548746ae9dfSNathan Whitehorn Elf_Addr **tp; 54927bd4146SNathan Whitehorn char *p; 55027bd4146SNathan Whitehorn 551746ae9dfSNathan Whitehorn __asm __volatile("mr %0,13" : "=r"(tp)); 55227bd4146SNathan Whitehorn p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 55327bd4146SNathan Whitehorn - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); 55427bd4146SNathan Whitehorn 55527bd4146SNathan Whitehorn return (p + TLS_DTV_OFFSET); 55627bd4146SNathan Whitehorn } 557