1*ce716eebSriastradh /* $NetBSD: mdreloc.c,v 1.60 2024/08/03 21:59:58 riastradh Exp $ */ 262926e7eSchristos 362926e7eSchristos /*- 4729925dfSmycroft * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. 562926e7eSchristos * All rights reserved. 662926e7eSchristos * 762926e7eSchristos * This code is derived from software contributed to The NetBSD Foundation 8bde7a965Smycroft * by Paul Kranenburg and by Charles M. Hannum. 962926e7eSchristos * 1062926e7eSchristos * Redistribution and use in source and binary forms, with or without 1162926e7eSchristos * modification, are permitted provided that the following conditions 1262926e7eSchristos * are met: 1362926e7eSchristos * 1. Redistributions of source code must retain the above copyright 1462926e7eSchristos * notice, this list of conditions and the following disclaimer. 1562926e7eSchristos * 2. Redistributions in binary form must reproduce the above copyright 1662926e7eSchristos * notice, this list of conditions and the following disclaimer in the 1762926e7eSchristos * documentation and/or other materials provided with the distribution. 1862926e7eSchristos * 1962926e7eSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2062926e7eSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2162926e7eSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2262926e7eSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2362926e7eSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2462926e7eSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2562926e7eSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2662926e7eSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2762926e7eSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2862926e7eSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2962926e7eSchristos * POSSIBILITY OF SUCH DAMAGE. 3062926e7eSchristos */ 3162926e7eSchristos 32ddde66e5Suwe /* 33ddde66e5Suwe * SPARC ELF relocations. 34ddde66e5Suwe * 35ddde66e5Suwe * Reference: 36ddde66e5Suwe * 37ddde66e5Suwe * SPARC Compliance Definition 2.4.1 38ddde66e5Suwe * http://sparc.org/wp-content/uploads/2014/01/SCD.2.4.1.pdf.gz 39ddde66e5Suwe */ 40ddde66e5Suwe 41680596d0Sskrll #include <sys/cdefs.h> 42680596d0Sskrll #ifndef lint 43*ce716eebSriastradh __RCSID("$NetBSD: mdreloc.c,v 1.60 2024/08/03 21:59:58 riastradh Exp $"); 44680596d0Sskrll #endif /* not lint */ 45680596d0Sskrll 462d65afd2Sjoerg #include <machine/elf_support.h> 472d65afd2Sjoerg 4862926e7eSchristos #include <errno.h> 4962926e7eSchristos #include <stdio.h> 5062926e7eSchristos #include <stdlib.h> 5162926e7eSchristos #include <string.h> 5262926e7eSchristos #include <unistd.h> 5362926e7eSchristos 5462926e7eSchristos #include "rtldenv.h" 5562926e7eSchristos #include "debug.h" 5662926e7eSchristos #include "rtld.h" 5762926e7eSchristos 5862926e7eSchristos /* 5962926e7eSchristos * The following table holds for each relocation type: 6062926e7eSchristos * - the width in bits of the memory location the relocation 6162926e7eSchristos * applies to (not currently used) 6262926e7eSchristos * - the number of bits the relocation value must be shifted to the 6362926e7eSchristos * right (i.e. discard least significant bits) to fit into 6462926e7eSchristos * the appropriate field in the instruction word. 6562926e7eSchristos * - flags indicating whether 6662926e7eSchristos * * the relocation involves a symbol 6762926e7eSchristos * * the relocation is relative to the current position 6862926e7eSchristos * * the relocation is for a GOT entry 6962926e7eSchristos * * the relocation is relative to the load address 7062926e7eSchristos * 7162926e7eSchristos */ 7262926e7eSchristos #define _RF_S 0x80000000 /* Resolve symbol */ 7362926e7eSchristos #define _RF_A 0x40000000 /* Use addend */ 7462926e7eSchristos #define _RF_P 0x20000000 /* Location relative */ 7562926e7eSchristos #define _RF_G 0x10000000 /* GOT offset */ 7662926e7eSchristos #define _RF_B 0x08000000 /* Load address relative */ 77995d8a8eSmartin #define _RF_U 0x04000000 /* Unaligned */ 7862926e7eSchristos #define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ 7962926e7eSchristos #define _RF_RS(s) ( (s) & 0xff) /* right shift */ 809f905ee4Smartin static const int reloc_target_flags[R_TYPE(TLS_TPOFF64)+1] = { 8162926e7eSchristos 0, /* NONE */ 8262926e7eSchristos _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */ 8362926e7eSchristos _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */ 8462926e7eSchristos _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */ 8562926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */ 8662926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */ 8762926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */ 8862926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */ 8962926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */ 9062926e7eSchristos _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */ 9162926e7eSchristos _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */ 9262926e7eSchristos _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */ 9362926e7eSchristos _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */ 9462926e7eSchristos _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */ 9562926e7eSchristos _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */ 9662926e7eSchristos _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ 9762926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */ 9862926e7eSchristos _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */ 9962926e7eSchristos _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ 10062926e7eSchristos _RF_SZ(32) | _RF_RS(0), /* COPY */ 10162926e7eSchristos _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ 10262926e7eSchristos _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ 10322001aeeSpk _RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */ 104995d8a8eSmartin _RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */ 1059f905ee4Smartin 1069f905ee4Smartin /* TLS and 64 bit relocs not listed here... */ 10762926e7eSchristos }; 10862926e7eSchristos 10962926e7eSchristos #ifdef RTLD_DEBUG_RELOC 11062926e7eSchristos static const char *reloc_names[] = { 11162926e7eSchristos "NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8", 11262926e7eSchristos "DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22", 11362926e7eSchristos "22", "13", "LO10", "GOT10", "GOT13", 11462926e7eSchristos "GOT22", "PC10", "PC22", "WPLT30", "COPY", 115dbbd50a9Snakayama "GLOB_DAT", "JMP_SLOT", "RELATIVE", "UA_32", 1169f905ee4Smartin 1179f905ee4Smartin /* not used with 32bit userland, besides a few of the TLS ones */ 1189f905ee4Smartin "PLT32", 1199f905ee4Smartin "HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", "PCPLT32", 1209f905ee4Smartin "10", "11", "64", "OLO10", "HH22", 1219f905ee4Smartin "HM10", "LM22", "PC_HH22", "PC_HM10", "PC_LM22", 1229f905ee4Smartin "WDISP16", "WDISP19", "GLOB_JMP", "7", "5", "6", 1239f905ee4Smartin "DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44", 1249f905ee4Smartin "L44", "REGISTER", "UA64", "UA16", 1259f905ee4Smartin "TLS_GD_HI22", "TLS_GD_LO10", "TLS_GD_ADD", "TLS_GD_CALL", 1269f905ee4Smartin "TLS_LDM_HI22", "TLS_LDM_LO10", "TLS_LDM_ADD", "TLS_LDM_CALL", 1279f905ee4Smartin "TLS_LDO_HIX22", "TLS_LDO_LOX10", "TLS_LDO_ADD", "TLS_IE_HI22", 1289f905ee4Smartin "TLS_IE_LO10", "TLS_IE_LD", "TLS_IE_LDX", "TLS_IE_ADD", "TLS_LE_HIX22", 1299f905ee4Smartin "TLS_LE_LOX10", "TLS_DTPMOD32", "TLS_DTPMOD64", "TLS_DTPOFF32", 1309f905ee4Smartin "TLS_DTPOFF64", "TLS_TPOFF32", "TLS_TPOFF64", 13162926e7eSchristos }; 13262926e7eSchristos #endif 13362926e7eSchristos 13462926e7eSchristos #define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) 13562926e7eSchristos #define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) 13622001aeeSpk #define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) 137995d8a8eSmartin #define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) 138995d8a8eSmartin #define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) 13962926e7eSchristos #define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) 14062926e7eSchristos #define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) 1419f905ee4Smartin #define RELOC_TLS(t) (t >= R_TYPE(TLS_GD_HI22)) 14262926e7eSchristos 1433eee01c5Smycroft static const int reloc_target_bitmask[] = { 14462926e7eSchristos #define _BM(x) (~(-(1ULL << (x)))) 14562926e7eSchristos 0, /* NONE */ 14662926e7eSchristos _BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */ 14762926e7eSchristos _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ 14862926e7eSchristos _BM(30), _BM(22), /* WDISP30, WDISP22 */ 14962926e7eSchristos _BM(22), _BM(22), /* HI22, _22 */ 15062926e7eSchristos _BM(13), _BM(10), /* RELOC_13, _LO10 */ 15162926e7eSchristos _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ 15262926e7eSchristos _BM(10), _BM(22), /* _PC10, _PC22 */ 15362926e7eSchristos _BM(30), 0, /* _WPLT30, _COPY */ 1545c519e87Spk -1, -1, -1, /* _GLOB_DAT, JMP_SLOT, _RELATIVE */ 1550a1196daSmartin _BM(32) /* _UA32 */ 15662926e7eSchristos #undef _BM 15762926e7eSchristos }; 15862926e7eSchristos #define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) 15962926e7eSchristos 160547bc13bSmycroft void _rtld_bind_start(void); 161aa1330ceSmycroft void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 1625f573ab6Sskrll caddr_t _rtld_bind(const Obj_Entry *, Elf_Word); 1639f486044Sskrll static inline int _rtld_relocate_plt_object(const Obj_Entry *, 1649f486044Sskrll const Elf_Rela *, Elf_Addr *); 16500c3ad1fSmycroft 16600c3ad1fSmycroft void 16700c3ad1fSmycroft _rtld_setup_pltgot(const Obj_Entry *obj) 16800c3ad1fSmycroft { 16900c3ad1fSmycroft /* 17000c3ad1fSmycroft * PLTGOT is the PLT on the sparc. 17100c3ad1fSmycroft * The first entry holds the call the dynamic linker. 17200c3ad1fSmycroft * We construct a `call' sequence that transfers 17300c3ad1fSmycroft * to `_rtld_bind_start()'. 17400c3ad1fSmycroft * The second entry holds the object identification. 17500c3ad1fSmycroft * Note: each PLT entry is three words long. 17600c3ad1fSmycroft */ 177f1c792d6Smycroft #define SAVE 0x9de3bfa0 /* i.e. `save %sp,-96,%sp' */ 17800c3ad1fSmycroft #define CALL 0x40000000 17900c3ad1fSmycroft #define NOP 0x01000000 18000c3ad1fSmycroft obj->pltgot[0] = SAVE; 18100c3ad1fSmycroft obj->pltgot[1] = CALL | 18200c3ad1fSmycroft ((Elf_Addr) &_rtld_bind_start - (Elf_Addr) &obj->pltgot[1]) >> 2; 18300c3ad1fSmycroft obj->pltgot[2] = NOP; 18400c3ad1fSmycroft obj->pltgot[3] = (Elf_Addr) obj; 18500c3ad1fSmycroft } 18600c3ad1fSmycroft 187aa1330ceSmycroft void 1885f573ab6Sskrll _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 189aa1330ceSmycroft { 190aa1330ceSmycroft const Elf_Rela *rela = 0, *relalim; 191aa1330ceSmycroft Elf_Addr relasz = 0; 192aa1330ceSmycroft Elf_Addr *where; 193aa1330ceSmycroft 194aa1330ceSmycroft for (; dynp->d_tag != DT_NULL; dynp++) { 195aa1330ceSmycroft switch (dynp->d_tag) { 196aa1330ceSmycroft case DT_RELA: 197aa1330ceSmycroft rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 198aa1330ceSmycroft break; 199aa1330ceSmycroft case DT_RELASZ: 200aa1330ceSmycroft relasz = dynp->d_un.d_val; 201aa1330ceSmycroft break; 202aa1330ceSmycroft } 203aa1330ceSmycroft } 204b4fba76bSlukem relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz); 205aa1330ceSmycroft for (; rela < relalim; rela++) { 206aa1330ceSmycroft where = (Elf_Addr *)(relocbase + rela->r_offset); 207aa1330ceSmycroft *where += (Elf_Addr)(relocbase + rela->r_addend); 208aa1330ceSmycroft } 209aa1330ceSmycroft } 210aa1330ceSmycroft 21100c3ad1fSmycroft int 212f40b256fSjoerg _rtld_relocate_nonplt_objects(Obj_Entry *obj) 21362926e7eSchristos { 21474444a2dSmycroft const Elf_Rela *rela; 215e45d4ba0Sjoerg const Elf_Sym *def = NULL; 216e45d4ba0Sjoerg const Obj_Entry *defobj = NULL; 217e45d4ba0Sjoerg unsigned long last_symnum = ULONG_MAX; 21874444a2dSmycroft 21974444a2dSmycroft for (rela = obj->rela; rela < obj->relalim; rela++) { 22074444a2dSmycroft Elf_Addr *where; 22162926e7eSchristos Elf_Word type, value, mask; 222bdc2ac15Smycroft unsigned long symnum; 22362926e7eSchristos 22474444a2dSmycroft where = (Elf_Addr *) (obj->relocbase + rela->r_offset); 22574444a2dSmycroft 22662926e7eSchristos type = ELF_R_TYPE(rela->r_info); 22762926e7eSchristos if (type == R_TYPE(NONE)) 2285f016a11Smycroft continue; 22962926e7eSchristos 230729925dfSmycroft /* We do JMP_SLOTs in _rtld_bind() below */ 23122001aeeSpk if (type == R_TYPE(JMP_SLOT)) 2325f016a11Smycroft continue; 23322001aeeSpk 234610e531eSjoerg /* IFUNC relocations are handled in _rtld_call_ifunc */ 235610e531eSjoerg if (type == R_TYPE(IRELATIVE)) { 236f80c3669Sjoerg if (obj->ifunc_remaining_nonplt == 0) { 237f80c3669Sjoerg obj->ifunc_remaining_nonplt = 238f80c3669Sjoerg obj->relalim - rela; 239f80c3669Sjoerg } 240610e531eSjoerg continue; 241610e531eSjoerg } 242610e531eSjoerg 2434e784905Spk /* COPY relocs are also handled elsewhere */ 2445c519e87Spk if (type == R_TYPE(COPY)) 2455f016a11Smycroft continue; 2465c519e87Spk 24762926e7eSchristos /* 24862926e7eSchristos * We use the fact that relocation types are an `enum' 2499f905ee4Smartin * Note: R_SPARC_TLS_TPOFF64 is currently numerically largest. 25062926e7eSchristos */ 2519f905ee4Smartin if (type > R_TYPE(TLS_TPOFF64)) 25262926e7eSchristos return (-1); 25362926e7eSchristos 2545c519e87Spk value = rela->r_addend; 2555c519e87Spk 256e45d4ba0Sjoerg if (RELOC_RESOLVE_SYMBOL(type) || RELOC_TLS(type)) { 257e45d4ba0Sjoerg symnum = ELF_R_SYM(rela->r_info); 258e45d4ba0Sjoerg if (last_symnum != symnum) { 259e45d4ba0Sjoerg last_symnum = symnum; 260e45d4ba0Sjoerg def = _rtld_find_symdef(symnum, obj, &defobj, 261e45d4ba0Sjoerg false); 262e45d4ba0Sjoerg if (def == NULL) 263e45d4ba0Sjoerg return -1; 264e45d4ba0Sjoerg } 265e45d4ba0Sjoerg } 266e45d4ba0Sjoerg 26762926e7eSchristos /* 2689f905ee4Smartin * Handle TLS relocations here, they are different. 2699f905ee4Smartin */ 2709f905ee4Smartin if (RELOC_TLS(type)) { 2719f905ee4Smartin switch (type) { 2729f905ee4Smartin case R_TYPE(TLS_DTPMOD32): 2739f905ee4Smartin *where = (Elf_Addr)defobj->tlsindex; 2749f905ee4Smartin 2759f905ee4Smartin rdbg(("TLS_DTPMOD32 %s in %s --> %p", 2769f905ee4Smartin obj->strtab + 2779f905ee4Smartin obj->symtab[symnum].st_name, 2789f905ee4Smartin obj->path, (void *)*where)); 2799f905ee4Smartin 2809f905ee4Smartin break; 2819f905ee4Smartin 2829f905ee4Smartin case R_TYPE(TLS_DTPOFF32): 2839f905ee4Smartin *where = (Elf_Addr)(def->st_value 2849f905ee4Smartin + rela->r_addend); 2859f905ee4Smartin 2869f905ee4Smartin rdbg(("TLS_DTPOFF32 %s in %s --> %p", 2879f905ee4Smartin obj->strtab + 2889f905ee4Smartin obj->symtab[symnum].st_name, 2899f905ee4Smartin obj->path, (void *)*where)); 2909f905ee4Smartin 2919f905ee4Smartin break; 2929f905ee4Smartin 2939f905ee4Smartin case R_TYPE(TLS_TPOFF32): 2943caa8dc7Sjoerg if (!defobj->tls_static && 2953caa8dc7Sjoerg _rtld_tls_offset_allocate(__UNCONST(defobj))) 2969f905ee4Smartin return -1; 2979f905ee4Smartin 2989f905ee4Smartin *where = (Elf_Addr)(def->st_value - 29928b12dabSjoerg defobj->tlsoffset + rela->r_addend); 3009f905ee4Smartin 3019f905ee4Smartin rdbg(("TLS_TPOFF32 %s in %s --> %p", 3029f905ee4Smartin obj->strtab + 3039f905ee4Smartin obj->symtab[symnum].st_name, 3049f905ee4Smartin obj->path, (void *)*where)); 3059f905ee4Smartin 3069f905ee4Smartin break; 3079f905ee4Smartin } 3089f905ee4Smartin continue; 3099f905ee4Smartin } 3109f905ee4Smartin 3119f905ee4Smartin /* 3129f905ee4Smartin * If it is no TLS relocation (handled above), we can not 313cb40c69bSandvar * deal with it if it is beyond R_SPARC_6. 3149f905ee4Smartin */ 3159f905ee4Smartin if (type > R_TYPE(6)) 3169f905ee4Smartin return (-1); 3179f905ee4Smartin 3189f905ee4Smartin /* 319aa1330ceSmycroft * Handle relative relocs here, as an optimization. 32062926e7eSchristos */ 321492895a9Smycroft if (type == R_TYPE(RELATIVE)) { 3225c519e87Spk *where += (Elf_Addr)(obj->relocbase + value); 323a3b892d1Smycroft rdbg(("RELATIVE in %s --> %p", obj->path, 324aa1330ceSmycroft (void *)*where)); 3255f016a11Smycroft continue; 32662926e7eSchristos } 32762926e7eSchristos 32862926e7eSchristos if (RELOC_RESOLVE_SYMBOL(type)) { 32962926e7eSchristos /* Add in the symbol's absolute address */ 33062926e7eSchristos value += (Elf_Word)(defobj->relocbase + def->st_value); 33162926e7eSchristos } 33262926e7eSchristos 33362926e7eSchristos if (RELOC_PC_RELATIVE(type)) { 33462926e7eSchristos value -= (Elf_Word)where; 33562926e7eSchristos } 33662926e7eSchristos 33722001aeeSpk if (RELOC_BASE_RELATIVE(type)) { 3384e784905Spk /* 33974444a2dSmycroft * Note that even though sparcs use `Elf_rela' 34074444a2dSmycroft * exclusively we still need the implicit memory addend 34174444a2dSmycroft * in relocations referring to GOT entries. 34274444a2dSmycroft * Undoubtedly, someone f*cked this up in the distant 34374444a2dSmycroft * past, and now we're stuck with it in the name of 34474444a2dSmycroft * compatibility for all eternity.. 3454e784905Spk * 34674444a2dSmycroft * In any case, the implicit and explicit should be 34774444a2dSmycroft * mutually exclusive. We provide a check for that 34874444a2dSmycroft * here. 3494e784905Spk */ 3504e784905Spk #define DIAGNOSTIC 3514e784905Spk #ifdef DIAGNOSTIC 3524e784905Spk if (value != 0 && *where != 0) { 3534e784905Spk xprintf("BASE_REL(%s): where=%p, *where 0x%x, " 3544e784905Spk "addend=0x%x, base %p\n", 3554e784905Spk obj->path, where, *where, 3564e784905Spk rela->r_addend, obj->relocbase); 3574e784905Spk } 3584e784905Spk #endif 3595c519e87Spk value += (Elf_Word)(obj->relocbase + *where); 36022001aeeSpk } 36122001aeeSpk 36262926e7eSchristos mask = RELOC_VALUE_BITMASK(type); 36362926e7eSchristos value >>= RELOC_VALUE_RIGHTSHIFT(type); 36462926e7eSchristos value &= mask; 36562926e7eSchristos 366995d8a8eSmartin if (RELOC_UNALIGNED(type)) { 367995d8a8eSmartin /* Handle unaligned relocations. */ 368995d8a8eSmartin Elf_Addr tmp = 0; 369995d8a8eSmartin char *ptr = (char *)where; 370995d8a8eSmartin int i, size = RELOC_TARGET_SIZE(type)/8; 371995d8a8eSmartin 372995d8a8eSmartin /* Read it in one byte at a time. */ 373995d8a8eSmartin for (i=0; i<size; i++) 374995d8a8eSmartin tmp = (tmp << 8) | ptr[i]; 375995d8a8eSmartin 376995d8a8eSmartin tmp &= ~mask; 377995d8a8eSmartin tmp |= value; 378995d8a8eSmartin 379995d8a8eSmartin /* Write it back out. */ 380995d8a8eSmartin for (i=0; i<size; i++) 381995d8a8eSmartin ptr[i] = ((tmp >> (8*i)) & 0xff); 382995d8a8eSmartin #ifdef RTLD_DEBUG_RELOC 383995d8a8eSmartin value = (Elf_Word)tmp; 384995d8a8eSmartin #endif 385995d8a8eSmartin 386995d8a8eSmartin } else { 38762926e7eSchristos *where &= ~mask; 38862926e7eSchristos *where |= value; 38962926e7eSchristos #ifdef RTLD_DEBUG_RELOC 390995d8a8eSmartin value = (Elf_Word)*where; 391995d8a8eSmartin #endif 392995d8a8eSmartin } 393995d8a8eSmartin #ifdef RTLD_DEBUG_RELOC 39462926e7eSchristos if (RELOC_RESOLVE_SYMBOL(type)) { 395a3b892d1Smycroft rdbg(("%s %s in %s --> %p in %s", reloc_names[type], 396151b6575Smartin obj->strtab + obj->symtab[ELF_R_SYM(rela->r_info)].st_name, 397995d8a8eSmartin obj->path, (void *)value, defobj->path)); 398ac191986Smycroft } else { 399a3b892d1Smycroft rdbg(("%s in %s --> %p", reloc_names[type], 400995d8a8eSmartin obj->path, (void *)value)); 40162926e7eSchristos } 40262926e7eSchristos #endif 40374444a2dSmycroft } 40462926e7eSchristos return (0); 40562926e7eSchristos } 406a04012e7Smycroft 407a04012e7Smycroft int 408e78cfb8eSjoerg _rtld_relocate_plt_lazy(Obj_Entry *obj) 409a04012e7Smycroft { 410610e531eSjoerg const Elf_Rela *rela; 411610e531eSjoerg 412610e531eSjoerg for (rela = obj->pltrelalim; rela-- > obj->pltrela; ) { 413610e531eSjoerg if (ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_IREL)) 414610e531eSjoerg obj->ifunc_remaining = obj->pltrelalim - rela + 1; 415610e531eSjoerg } 416610e531eSjoerg 417610e531eSjoerg return 0; 418610e531eSjoerg } 419610e531eSjoerg 420729925dfSmycroft caddr_t 4215f573ab6Sskrll _rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 422729925dfSmycroft { 423b4fba76bSlukem const Elf_Rela *rela = (const Elf_Rela *)((const uint8_t *)obj->pltrela + reloff); 4240a1196daSmartin Elf_Addr value; 4250a1196daSmartin int err; 4260a1196daSmartin 42782f77330Smrg value = 0; /* XXX gcc */ 42882f77330Smrg 429cb1cd7e8Sjoerg _rtld_shared_enter(); 4300a1196daSmartin err = _rtld_relocate_plt_object(obj, rela, &value); 43112bd4dbdSchristos if (err) 4320a1196daSmartin _rtld_die(); 433cb1cd7e8Sjoerg _rtld_shared_exit(); 4340a1196daSmartin 4350a1196daSmartin return (caddr_t)value; 4360a1196daSmartin } 4370a1196daSmartin 4380a1196daSmartin int 4390a1196daSmartin _rtld_relocate_plt_objects(const Obj_Entry *obj) 4400a1196daSmartin { 4410a1196daSmartin const Elf_Rela *rela = obj->pltrela; 4420a1196daSmartin 4430a1196daSmartin for (; rela < obj->pltrelalim; rela++) 4440a1196daSmartin if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 4450a1196daSmartin return -1; 4460a1196daSmartin 4470a1196daSmartin return 0; 4480a1196daSmartin } 4490a1196daSmartin 4500a1196daSmartin static inline int 4510a1196daSmartin _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *tp) 4520a1196daSmartin { 453729925dfSmycroft const Elf_Sym *def; 454729925dfSmycroft const Obj_Entry *defobj; 4556bff9ffcSmycroft Elf_Word *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 456729925dfSmycroft Elf_Addr value; 45712bd4dbdSchristos unsigned long info = rela->r_info; 458729925dfSmycroft 459610e531eSjoerg if (ELF_R_TYPE(info) == R_TYPE(JMP_IREL)) 460610e531eSjoerg return 0; 461610e531eSjoerg 46212bd4dbdSchristos assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); 463729925dfSmycroft 46412bd4dbdSchristos def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); 46512bd4dbdSchristos if (__predict_false(def == NULL)) 4660a1196daSmartin return -1; 46712bd4dbdSchristos if (__predict_false(def == &_rtld_sym_zero)) 46812bd4dbdSchristos return 0; 469729925dfSmycroft 4707a1a6f1cSjoerg if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 4717a1a6f1cSjoerg if (tp == NULL) 4727a1a6f1cSjoerg return 0; 4737a1a6f1cSjoerg value = _rtld_resolve_ifunc(defobj, def); 4747a1a6f1cSjoerg } else { 475729925dfSmycroft value = (Elf_Addr)(defobj->relocbase + def->st_value); 4767a1a6f1cSjoerg } 477723a5f8aSmycroft rdbg(("bind now/fixup in %s --> new=%p", 478723a5f8aSmycroft defobj->strtab + def->st_name, (void *)value)); 479729925dfSmycroft 4802d65afd2Sjoerg sparc_write_branch(where + 1, (void *)value); 481729925dfSmycroft 4820a1196daSmartin if (tp) 4830a1196daSmartin *tp = value; 4840a1196daSmartin 4850a1196daSmartin return 0; 486729925dfSmycroft } 487