1219532Smarius/* $NetBSD: mdreloc.c,v 1.42 2008/04/28 20:23:04 martin Exp $ */ 292195Sjake 392195Sjake/*- 492195Sjake * Copyright (c) 2000 Eduardo Horvath. 592195Sjake * Copyright (c) 1999 The NetBSD Foundation, Inc. 692195Sjake * All rights reserved. 792195Sjake * 892195Sjake * This code is derived from software contributed to The NetBSD Foundation 992195Sjake * by Paul Kranenburg. 1092195Sjake * 1192195Sjake * Redistribution and use in source and binary forms, with or without 1292195Sjake * modification, are permitted provided that the following conditions 1392195Sjake * are met: 1492195Sjake * 1. Redistributions of source code must retain the above copyright 1592195Sjake * notice, this list of conditions and the following disclaimer. 1692195Sjake * 2. Redistributions in binary form must reproduce the above copyright 1792195Sjake * notice, this list of conditions and the following disclaimer in the 1892195Sjake * documentation and/or other materials provided with the distribution. 1992195Sjake * 2092195Sjake * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2192195Sjake * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2292195Sjake * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2392195Sjake * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2492195Sjake * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2592195Sjake * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2692195Sjake * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2792195Sjake * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2892195Sjake * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2992195Sjake * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3092195Sjake * POSSIBILITY OF SUCH DAMAGE. 3192195Sjake */ 3292195Sjake 33172708Smarius#include <sys/cdefs.h> 34172708Smarius__FBSDID("$FreeBSD: stable/10/libexec/rtld-elf/sparc64/reloc.c 331206 2018-03-19 14:28:58Z marius $"); 35172708Smarius 3698724Sjake#include <sys/param.h> 3798724Sjake#include <sys/mman.h> 3898724Sjake 3992195Sjake#include <errno.h> 4092195Sjake#include <stdio.h> 4192195Sjake#include <stdlib.h> 4292195Sjake#include <string.h> 4392195Sjake#include <unistd.h> 4492195Sjake 4592195Sjake#include "debug.h" 4692195Sjake#include "rtld.h" 4792195Sjake 4892195Sjake/* 4992195Sjake * The following table holds for each relocation type: 5092195Sjake * - the width in bits of the memory location the relocation 5192195Sjake * applies to (not currently used) 5292195Sjake * - the number of bits the relocation value must be shifted to the 5392195Sjake * right (i.e. discard least significant bits) to fit into 5492195Sjake * the appropriate field in the instruction word. 5592195Sjake * - flags indicating whether 5692195Sjake * * the relocation involves a symbol 5792195Sjake * * the relocation is relative to the current position 5892195Sjake * * the relocation is for a GOT entry 5992195Sjake * * the relocation is relative to the load address 6092195Sjake * 6192195Sjake */ 62219532Smarius#define _RF_S 0x80000000 /* Resolve symbol */ 63219532Smarius#define _RF_A 0x40000000 /* Use addend */ 64219532Smarius#define _RF_P 0x20000000 /* Location relative */ 65219532Smarius#define _RF_G 0x10000000 /* GOT offset */ 66219532Smarius#define _RF_B 0x08000000 /* Load address relative */ 67219532Smarius#define _RF_U 0x04000000 /* Unaligned */ 68219532Smarius#define _RF_X 0x02000000 /* Bare symbols, needs proc */ 69219533Smarius#define _RF_D 0x01000000 /* Use dynamic TLS offset */ 70219533Smarius#define _RF_O 0x00800000 /* Use static TLS offset */ 71219533Smarius#define _RF_I 0x00400000 /* Use TLS object ID */ 72219532Smarius#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ 73219532Smarius#define _RF_RS(s) ( (s) & 0xff) /* right shift */ 74172708Smariusstatic const int reloc_target_flags[] = { 7592195Sjake 0, /* NONE */ 76219532Smarius _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* 8 */ 77219532Smarius _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* 16 */ 78219532Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 32 */ 7992195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */ 8092195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */ 8192195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */ 8292195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */ 8392195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */ 84219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* HI22 */ 85219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 22 */ 86219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 13 */ 87219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* LO10 */ 8892195Sjake _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */ 8992195Sjake _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */ 9092195Sjake _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ 9192195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */ 9292195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */ 9392195Sjake _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ 9492195Sjake _RF_SZ(32) | _RF_RS(0), /* COPY */ 9592195Sjake _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ 9692195Sjake _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ 9792195Sjake _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* RELATIVE */ 9892195Sjake _RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */ 9992195Sjake 10092195Sjake _RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */ 10192195Sjake _RF_A| _RF_SZ(32) | _RF_RS(10), /* HIPLT22 */ 10292195Sjake _RF_A| _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */ 10392195Sjake _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */ 10492195Sjake _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PCPLT22 */ 10592195Sjake _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT10 */ 106219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 10 */ 107219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 11 */ 108219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(64) | _RF_RS(0), /* 64 */ 10992195Sjake _RF_S|_RF_A|/*extra*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */ 110219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(42), /* HH22 */ 111219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(32), /* HM10 */ 112219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* LM22 */ 11392195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(42), /* PC_HH22 */ 11492195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(32), /* PC_HM10 */ 11592195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC_LM22 */ 11692195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP16 */ 11792195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP19 */ 11892195Sjake _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */ 119219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 7 */ 120219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 5 */ 121219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 6 */ 12292195Sjake _RF_S|_RF_A|_RF_P| _RF_SZ(64) | _RF_RS(0), /* DISP64 */ 12392195Sjake _RF_A| _RF_SZ(64) | _RF_RS(0), /* PLT64 */ 124219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* HIX22 */ 125219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* LOX10 */ 126219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(22), /* H44 */ 127219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(12), /* M44 */ 128219532Smarius _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* L44 */ 12992195Sjake _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */ 13092195Sjake _RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */ 13192195Sjake _RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */ 132219533Smarius 133219533Smarius /* TLS */ 134219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* GD_HI22 */ 135219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GD_LO10 */ 136219533Smarius 0, /* GD_ADD */ 137219533Smarius _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* GD_CALL */ 138219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDM_HI22 */ 139219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDM_LO10 */ 140219533Smarius 0, /* LDM_ADD */ 141219533Smarius _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* LDM_CALL */ 142219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDO_HIX22 */ 143219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDO_LOX10 */ 144219533Smarius 0, /* LDO_ADD */ 145219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* IE_HI22 */ 146219533Smarius _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* IE_LO10 */ 147219533Smarius 0, /* IE_LD */ 148219533Smarius 0, /* IE_LDX */ 149219533Smarius 0, /* IE_ADD */ 150219533Smarius _RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(10), /* LE_HIX22 */ 151219533Smarius _RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* LE_LOX10 */ 152219533Smarius _RF_S| _RF_I| _RF_SZ(32) | _RF_RS(0), /* DTPMOD32 */ 153219533Smarius _RF_S| _RF_I| _RF_SZ(64) | _RF_RS(0), /* DTPMOD64 */ 154219533Smarius _RF_S|_RF_A| _RF_D| _RF_SZ(32) | _RF_RS(0), /* DTPOFF32 */ 155219533Smarius _RF_S|_RF_A| _RF_D| _RF_SZ(64) | _RF_RS(0), /* DTPOFF64 */ 156219533Smarius _RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* TPOFF32 */ 157219533Smarius _RF_S|_RF_A| _RF_O| _RF_SZ(64) | _RF_RS(0) /* TPOFF64 */ 15892195Sjake}; 15992195Sjake 16092195Sjake#if 0 161219532Smariusstatic const char *const reloc_names[] = { 162219532Smarius "NONE", "8", "16", "32", "DISP_8", "DISP_16", "DISP_32", "WDISP_30", 163219532Smarius "WDISP_22", "HI22", "22", "13", "LO10", "GOT10", "GOT13", "GOT22", 164219532Smarius "PC10", "PC22", "WPLT30", "COPY", "GLOB_DAT", "JMP_SLOT", "RELATIVE", 165219532Smarius "UA_32", "PLT32", "HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", 166219532Smarius "PCPLT32", "10", "11", "64", "OLO10", "HH22", "HM10", "LM22", 167219532Smarius "PC_HH22", "PC_HM10", "PC_LM22", "WDISP16", "WDISP19", "GLOB_JMP", 168219532Smarius "7", "5", "6", "DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44", 169219533Smarius "L44", "REGISTER", "UA64", "UA16", "GD_HI22", "GD_LO10", "GD_ADD", 170219533Smarius "GD_CALL", "LDM_HI22", "LDMO10", "LDM_ADD", "LDM_CALL", "LDO_HIX22", 171219533Smarius "LDO_LOX10", "LDO_ADD", "IE_HI22", "IE_LO10", "IE_LD", "IE_LDX", 172219533Smarius "IE_ADD", "LE_HIX22", "LE_LOX10", "DTPMOD32", "DTPMOD64", "DTPOFF32", 173219533Smarius "DTPOFF64", "TPOFF32", "TPOFF64" 17492195Sjake}; 17592195Sjake#endif 17692195Sjake 177219532Smarius#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) 178219532Smarius#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) 179219532Smarius#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) 180219532Smarius#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) 181219532Smarius#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) 182219532Smarius#define RELOC_BARE_SYMBOL(t) ((reloc_target_flags[t] & _RF_X) != 0) 183219533Smarius#define RELOC_USE_TLS_DOFF(t) ((reloc_target_flags[t] & _RF_D) != 0) 184219533Smarius#define RELOC_USE_TLS_OFF(t) ((reloc_target_flags[t] & _RF_O) != 0) 185219533Smarius#define RELOC_USE_TLS_ID(t) ((reloc_target_flags[t] & _RF_I) != 0) 186219532Smarius#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) 187219532Smarius#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) 18892195Sjake 189172708Smariusstatic const long reloc_target_bitmask[] = { 190219532Smarius#define _BM(x) (~(-(1ULL << (x)))) 19192195Sjake 0, /* NONE */ 192219532Smarius _BM(8), _BM(16), _BM(32), /* 8, 16, 32 */ 19392195Sjake _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ 19492195Sjake _BM(30), _BM(22), /* WDISP30, WDISP22 */ 195219339Smarius _BM(22), _BM(22), /* HI22, 22 */ 196219532Smarius _BM(13), _BM(10), /* 13, LO10 */ 19792195Sjake _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ 198219339Smarius _BM(10), _BM(22), /* PC10, PC22 */ 199219339Smarius _BM(30), 0, /* WPLT30, COPY */ 200219339Smarius _BM(32), _BM(32), _BM(32), /* GLOB_DAT, JMP_SLOT, RELATIVE */ 201219339Smarius _BM(32), _BM(32), /* UA32, PLT32 */ 202219339Smarius _BM(22), _BM(10), /* HIPLT22, LOPLT10 */ 203219339Smarius _BM(32), _BM(22), _BM(10), /* PCPLT32, PCPLT22, PCPLT10 */ 204219339Smarius _BM(10), _BM(11), -1, /* 10, 11, 64 */ 205219339Smarius _BM(13), _BM(22), /* OLO10, HH22 */ 206219339Smarius _BM(10), _BM(22), /* HM10, LM22 */ 207219339Smarius _BM(22), _BM(10), _BM(22), /* PC_HH22, PC_HM10, PC_LM22 */ 208219339Smarius _BM(16), _BM(19), /* WDISP16, WDISP19 */ 20992195Sjake -1, /* GLOB_JMP */ 210219339Smarius _BM(7), _BM(5), _BM(6), /* 7, 5, 6 */ 21192195Sjake -1, -1, /* DISP64, PLT64 */ 21292195Sjake _BM(22), _BM(13), /* HIX22, LOX10 */ 21392195Sjake _BM(22), _BM(10), _BM(13), /* H44, M44, L44 */ 21492195Sjake -1, -1, _BM(16), /* REGISTER, UA64, UA16 */ 215219533Smarius _BM(22), _BM(10), 0, _BM(30), /* GD_HI22, GD_LO10, GD_ADD, GD_CALL */ 216219533Smarius _BM(22), _BM(10), 0, /* LDM_HI22, LDMO10, LDM_ADD */ 217219533Smarius _BM(30), /* LDM_CALL */ 218219533Smarius _BM(22), _BM(10), 0, /* LDO_HIX22, LDO_LOX10, LDO_ADD */ 219219533Smarius _BM(22), _BM(10), 0, 0, /* IE_HI22, IE_LO10, IE_LD, IE_LDX */ 220219533Smarius 0, /* IE_ADD */ 221219533Smarius _BM(22), _BM(13), /* LE_HIX22, LE_LOX10 */ 222219533Smarius _BM(32), -1, /* DTPMOD32, DTPMOD64 */ 223219533Smarius _BM(32), -1, /* DTPOFF32, DTPOFF64 */ 224219533Smarius _BM(32), -1 /* TPOFF32, TPOFF64 */ 22592195Sjake#undef _BM 22692195Sjake}; 227219532Smarius#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) 22892195Sjake 22992195Sjake#undef flush 230219532Smarius#define flush(va, offs) \ 23192195Sjake __asm __volatile("flush %0 + %1" : : "r" (va), "I" (offs)); 23292195Sjake 23392195Sjakestatic int reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, 234233231Skib SymCache *cache, int flags, RtldLockState *lockstate); 235153504Smarcelstatic void install_plt(Elf_Word *pltgot, Elf_Addr proc); 23692195Sjake 23792195Sjakeextern char _rtld_bind_start_0[]; 23892195Sjakeextern char _rtld_bind_start_1[]; 23992195Sjake 24092195Sjakeint 24192195Sjakedo_copy_relocations(Obj_Entry *dstobj) 24292195Sjake{ 24392195Sjake const Elf_Rela *relalim; 24492195Sjake const Elf_Rela *rela; 24592195Sjake const Elf_Sym *dstsym; 24692195Sjake const Elf_Sym *srcsym; 24792195Sjake void *dstaddr; 24892195Sjake const void *srcaddr; 249216695Skib const Obj_Entry *srcobj, *defobj; 250216695Skib SymLook req; 25192195Sjake const char *name; 25292195Sjake size_t size; 253216695Skib int res; 25492195Sjake 25592195Sjake assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ 25692195Sjake 25792195Sjake relalim = (const Elf_Rela *)((caddr_t)dstobj->rela + dstobj->relasize); 25892195Sjake for (rela = dstobj->rela; rela < relalim; rela++) { 25992195Sjake if (ELF_R_TYPE(rela->r_info) == R_SPARC_COPY) { 26092195Sjake dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 26192195Sjake dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 26292195Sjake name = dstobj->strtab + dstsym->st_name; 26392195Sjake size = dstsym->st_size; 264216695Skib symlook_init(&req, name); 265216695Skib req.ventry = fetch_ventry(dstobj, 266216695Skib ELF_R_SYM(rela->r_info)); 267233231Skib req.flags = SYMLOOK_EARLY; 26892195Sjake 269296727Skib for (srcobj = globallist_next(dstobj); srcobj != NULL; 270296727Skib srcobj = globallist_next(srcobj)) { 271216695Skib res = symlook_obj(&req, srcobj); 272216695Skib if (res == 0) { 273216695Skib srcsym = req.sym_out; 274216695Skib defobj = req.defobj_out; 27592195Sjake break; 276216695Skib } 277216695Skib } 27892195Sjake if (srcobj == NULL) { 27992195Sjake _rtld_error("Undefined symbol \"%s\"" 28092195Sjake "referenced from COPY relocation" 28192195Sjake "in %s", name, dstobj->path); 28292195Sjake return (-1); 28392195Sjake } 28492195Sjake 285216695Skib srcaddr = (const void *)(defobj->relocbase + 28692195Sjake srcsym->st_value); 28792195Sjake memcpy(dstaddr, srcaddr, size); 28892195Sjake } 28992195Sjake } 29092195Sjake 29192195Sjake return (0); 29292195Sjake} 29392195Sjake 29492195Sjakeint 295233231Skibreloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 296233231Skib RtldLockState *lockstate) 29792195Sjake{ 29892195Sjake const Elf_Rela *relalim; 29992195Sjake const Elf_Rela *rela; 30092195Sjake SymCache *cache; 30198629Sdillon int r = -1; 30292195Sjake 303271469Skib if ((flags & SYMLOOK_IFUNC) != 0) 304271469Skib /* XXX not implemented */ 305271469Skib return (0); 306271469Skib 30798629Sdillon /* 30898629Sdillon * The dynamic loader may be called from a thread, we have 30998629Sdillon * limited amounts of stack available so we cannot use alloca(). 31098629Sdillon */ 311171432Skensmith if (obj != obj_rtld) { 312234841Skib cache = calloc(obj->dynsymcount, sizeof(SymCache)); 313208256Srdivacky /* No need to check for NULL here */ 314171432Skensmith } else 31598629Sdillon cache = NULL; 31692195Sjake 31792195Sjake relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 31892195Sjake for (rela = obj->rela; rela < relalim; rela++) { 319233231Skib if (reloc_nonplt_object(obj, rela, cache, flags, lockstate) < 0) 32098629Sdillon goto done; 32192195Sjake } 32298629Sdillon r = 0; 32398629Sdillondone: 324208256Srdivacky if (cache != NULL) 325208256Srdivacky free(cache); 32698629Sdillon return (r); 32792195Sjake} 32892195Sjake 32992195Sjakestatic int 330216695Skibreloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache, 331233231Skib int flags, RtldLockState *lockstate) 33292195Sjake{ 33392195Sjake const Obj_Entry *defobj; 33492195Sjake const Elf_Sym *def; 33592195Sjake Elf_Addr *where; 336153504Smarcel Elf_Word *where32; 33792195Sjake Elf_Word type; 33892195Sjake Elf_Addr value; 33992195Sjake Elf_Addr mask; 340115396Skan 34192195Sjake where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 342153504Smarcel where32 = (Elf_Word *)where; 34392195Sjake defobj = NULL; 34492195Sjake def = NULL; 34592195Sjake 346172708Smarius type = ELF64_R_TYPE_ID(rela->r_info); 34792195Sjake if (type == R_SPARC_NONE) 34892195Sjake return (0); 34992195Sjake 350219339Smarius /* We do JMP_SLOTs below. */ 35192195Sjake if (type == R_SPARC_JMP_SLOT) 35292195Sjake return (0); 35392195Sjake 354219339Smarius /* COPY relocs are also handled elsewhere. */ 35592195Sjake if (type == R_SPARC_COPY) 35692195Sjake return (0); 35792195Sjake 358219533Smarius /* Ignore ADD and CALL relocations for dynamic TLS references. */ 359219533Smarius if (type == R_SPARC_TLS_GD_ADD || type == R_SPARC_TLS_GD_CALL || 360219533Smarius type == R_SPARC_TLS_LDM_ADD || type == R_SPARC_TLS_LDM_CALL || 361219533Smarius type == R_SPARC_TLS_LDO_ADD) 362219533Smarius return (0); 363219533Smarius 36492195Sjake /* 365219533Smarius * Note: R_SPARC_TLS_TPOFF64 must be the numerically largest 366219533Smarius * relocation type. 36792195Sjake */ 368331206Smarius if (type >= nitems(reloc_target_bitmask)) { 369219533Smarius _rtld_error("%s: Unsupported relocation type %d in non-PLT " 370219533Smarius "object\n", obj->path, type); 37192195Sjake return (-1); 372219533Smarius } 37392195Sjake 37492195Sjake value = rela->r_addend; 37592195Sjake 37692195Sjake /* 377219339Smarius * Handle relative relocs here, because we might not be able to access 378219339Smarius * globals yet. 37992195Sjake */ 38092195Sjake if (type == R_SPARC_RELATIVE) { 381219339Smarius /* XXXX -- apparently we ignore the preexisting value. */ 38292195Sjake *where = (Elf_Addr)(obj->relocbase + value); 38392195Sjake return (0); 38492195Sjake } 38592195Sjake 38692195Sjake /* 38792195Sjake * If we get here while relocating rtld itself, we will crash because 38892195Sjake * a non-local variable is accessed. 38992195Sjake */ 39092195Sjake if (RELOC_RESOLVE_SYMBOL(type)) { 391219339Smarius /* Find the symbol. */ 39292195Sjake def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 393233231Skib flags, cache, lockstate); 39492195Sjake if (def == NULL) 39592195Sjake return (-1); 39692195Sjake 397219533Smarius if (RELOC_USE_TLS_ID(type)) 398219533Smarius value = (Elf_Addr)defobj->tlsindex; 399219533Smarius else if (RELOC_USE_TLS_DOFF(type)) 400219533Smarius value += (Elf_Addr)def->st_value; 401219533Smarius else if (RELOC_USE_TLS_OFF(type)) { 402219533Smarius /* 403219533Smarius * We lazily allocate offsets for static TLS as we 404219533Smarius * see the first relocation that references the TLS 405219533Smarius * block. This allows us to support (small amounts 406219533Smarius * of) static TLS in dynamically loaded modules. If 407219533Smarius * we run out of space, we generate an error. 408219533Smarius */ 409219533Smarius if (!defobj->tls_done && 410219533Smarius !allocate_tls_offset((Obj_Entry*)defobj)) { 411219533Smarius _rtld_error("%s: No space available for " 412219533Smarius "static Thread Local Storage", obj->path); 413219533Smarius return (-1); 414219533Smarius } 415219533Smarius value += (Elf_Addr)(def->st_value - 416219533Smarius defobj->tlsoffset); 417219533Smarius } else { 418219533Smarius /* Add in the symbol's absolute address. */ 419219533Smarius value += (Elf_Addr)(def->st_value + 420219533Smarius defobj->relocbase); 421219533Smarius } 42292195Sjake } 42392195Sjake 424172708Smarius if (type == R_SPARC_OLO10) 425172708Smarius value = (value & 0x3ff) + ELF64_R_TYPE_DATA(rela->r_info); 426172708Smarius 427219533Smarius if (type == R_SPARC_HIX22 || type == R_SPARC_TLS_LE_HIX22) 428219340Smarius value ^= 0xffffffffffffffff; 429219340Smarius 43092195Sjake if (RELOC_PC_RELATIVE(type)) 43192195Sjake value -= (Elf_Addr)where; 43292195Sjake 43392195Sjake if (RELOC_BASE_RELATIVE(type)) { 43492195Sjake /* 43592195Sjake * Note that even though sparcs use `Elf_rela' exclusively 43692195Sjake * we still need the implicit memory addend in relocations 437219532Smarius * referring to GOT entries. Undoubtedly, someone f*cked 43892195Sjake * this up in the distant past, and now we're stuck with 439219532Smarius * it in the name of compatibility for all eternity ... 44092195Sjake * 44192195Sjake * In any case, the implicit and explicit should be mutually 442219532Smarius * exclusive. We provide a check for that here. 44392195Sjake */ 44492195Sjake /* XXXX -- apparently we ignore the preexisting value */ 44592195Sjake value += (Elf_Addr)(obj->relocbase); 44692195Sjake } 44792195Sjake 44892195Sjake mask = RELOC_VALUE_BITMASK(type); 44992195Sjake value >>= RELOC_VALUE_RIGHTSHIFT(type); 45092195Sjake value &= mask; 45192195Sjake 452219533Smarius if (type == R_SPARC_LOX10 || type == R_SPARC_TLS_LE_LOX10) 453219533Smarius value |= 0x1c00; 454219533Smarius 45592195Sjake if (RELOC_UNALIGNED(type)) { 45692195Sjake /* Handle unaligned relocations. */ 45792195Sjake Elf_Addr tmp; 45892195Sjake char *ptr; 45992195Sjake int size; 46092195Sjake int i; 461115396Skan 46292195Sjake size = RELOC_TARGET_SIZE(type) / 8; 46392195Sjake ptr = (char *)where; 46492195Sjake tmp = 0; 465115396Skan 46692195Sjake /* Read it in one byte at a time. */ 46792195Sjake for (i = 0; i < size; i++) 46892195Sjake tmp = (tmp << 8) | ptr[i]; 46992195Sjake 47092195Sjake tmp &= ~mask; 47192195Sjake tmp |= value; 47292195Sjake 47392195Sjake /* Write it back out. */ 47492195Sjake for (i = 0; i < size; i++) 475107638Skan ptr[i] = ((tmp >> ((size - i - 1) * 8)) & 0xff); 47692195Sjake } else if (RELOC_TARGET_SIZE(type) > 32) { 47792195Sjake *where &= ~mask; 47892195Sjake *where |= value; 47992195Sjake } else { 48092195Sjake *where32 &= ~mask; 48192195Sjake *where32 |= value; 48292195Sjake } 48392195Sjake 48492195Sjake return (0); 48592195Sjake} 48692195Sjake 48792195Sjakeint 48892195Sjakereloc_plt(Obj_Entry *obj) 48992195Sjake{ 49092195Sjake#if 0 49192195Sjake const Obj_Entry *defobj; 49292195Sjake const Elf_Rela *relalim; 49392195Sjake const Elf_Rela *rela; 49492195Sjake const Elf_Sym *def; 49592195Sjake Elf_Addr *where; 49692195Sjake Elf_Addr value; 49792195Sjake 49892195Sjake relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 49992195Sjake for (rela = obj->pltrela; rela < relalim; rela++) { 50092195Sjake if (rela->r_addend == 0) 50192195Sjake continue; 502172708Smarius assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); 50392195Sjake where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 50492195Sjake def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 505309371Sjhb SYMLOOK_IN_PLT, NULL, lockstate); 50692195Sjake value = (Elf_Addr)(defobj->relocbase + def->st_value); 50792195Sjake *where = value; 50892195Sjake } 50992195Sjake#endif 51092195Sjake return (0); 51192195Sjake} 51292195Sjake 51392195Sjake/* 51492195Sjake * Instruction templates: 51592195Sjake */ 51692195Sjake#define BAA 0x10400000 /* ba,a %xcc, 0 */ 51792195Sjake#define SETHI 0x03000000 /* sethi %hi(0), %g1 */ 51892195Sjake#define JMP 0x81c06000 /* jmpl %g1+%lo(0), %g0 */ 51992195Sjake#define NOP 0x01000000 /* sethi %hi(0), %g0 */ 52092195Sjake#define OR 0x82806000 /* or %g1, 0, %g1 */ 52192195Sjake#define XOR 0x82c06000 /* xor %g1, 0, %g1 */ 52292195Sjake#define MOV71 0x8283a000 /* or %o7, 0, %g1 */ 52392195Sjake#define MOV17 0x9c806000 /* or %g1, 0, %o7 */ 52492195Sjake#define CALL 0x40000000 /* call 0 */ 52592195Sjake#define SLLX 0x8b407000 /* sllx %g1, 0, %g1 */ 52692195Sjake#define SETHIG5 0x0b000000 /* sethi %hi(0), %g5 */ 52792195Sjake#define ORG5 0x82804005 /* or %g1, %g5, %g1 */ 52892195Sjake 52992195Sjake/* %hi(v) with variable shift */ 53092195Sjake#define HIVAL(v, s) (((v) >> (s)) & 0x003fffff) 531219532Smarius#define LOVAL(v) ((v) & 0x000003ff) 53292195Sjake 53392195Sjakeint 534233231Skibreloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 53592195Sjake{ 53692195Sjake const Obj_Entry *defobj; 53792195Sjake const Elf_Rela *relalim; 53892195Sjake const Elf_Rela *rela; 53992195Sjake const Elf_Sym *def; 54092195Sjake Elf_Addr *where; 54192195Sjake Elf_Addr target; 54292195Sjake 54392195Sjake relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 54492195Sjake for (rela = obj->pltrela; rela < relalim; rela++) { 545172708Smarius assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); 54692195Sjake where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 54792195Sjake def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 548233231Skib SYMLOOK_IN_PLT | flags, NULL, lockstate); 549103315Stmm if (def == NULL) 550103315Stmm return -1; 55192195Sjake target = (Elf_Addr)(defobj->relocbase + def->st_value); 552107071Stmm reloc_jmpslot(where, target, defobj, obj, (Elf_Rel *)rela); 55392195Sjake } 55492195Sjake obj->jmpslots_done = true; 55592195Sjake return (0); 55692195Sjake} 55792195Sjake 558228435Skibint 559228435Skibreloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 560228435Skib{ 561228435Skib 562228435Skib /* XXX not implemented */ 563228435Skib return (0); 564228435Skib} 565228435Skib 566228435Skibint 567233231Skibreloc_gnu_ifunc(Obj_Entry *obj, int flags, 568233231Skib struct Struct_RtldLockState *lockstate) 569228435Skib{ 570228435Skib 571228435Skib /* XXX not implemented */ 572228435Skib return (0); 573228435Skib} 574228435Skib 57592195SjakeElf_Addr 576107071Stmmreloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *obj, 577219339Smarius const Obj_Entry *refobj, const Elf_Rel *rel) 57892195Sjake{ 579107071Stmm const Elf_Rela *rela = (const Elf_Rela *)rel; 58092195Sjake Elf_Addr offset; 581153504Smarcel Elf_Word *where; 58292195Sjake 583107071Stmm if (rela - refobj->pltrela < 32764) { 584107071Stmm /* 585107071Stmm * At the PLT entry pointed at by `where', we now construct 586107071Stmm * a direct transfer to the now fully resolved function 587107071Stmm * address. 58892195Sjake * 589107071Stmm * A PLT entry is supposed to start by looking like this: 59092195Sjake * 591107071Stmm * sethi (. - .PLT0), %g1 592107071Stmm * ba,a %xcc, .PLT1 59392195Sjake * nop 59492195Sjake * nop 59592195Sjake * nop 59692195Sjake * nop 59792195Sjake * nop 59892195Sjake * nop 59992195Sjake * 600107071Stmm * When we replace these entries we start from the second 601107071Stmm * entry and do it in reverse order so the last thing we 602107071Stmm * do is replace the branch. That allows us to change this 603107071Stmm * atomically. 60492195Sjake * 605107071Stmm * We now need to find out how far we need to jump. We 606107071Stmm * have a choice of several different relocation techniques 607107071Stmm * which are increasingly expensive. 60892195Sjake */ 609153504Smarcel where = (Elf_Word *)wherep; 610107071Stmm offset = ((Elf_Addr)where) - target; 611107071Stmm if (offset <= (1L<<20) && offset >= -(1L<<20)) { 612115396Skan /* 613219532Smarius * We're within 1MB -- we can use a direct branch 614219532Smarius * instruction. 615107071Stmm * 616107071Stmm * We can generate this pattern: 617107071Stmm * 618107071Stmm * sethi %hi(. - .PLT0), %g1 619107071Stmm * ba,a %xcc, addr 620107071Stmm * nop 621107071Stmm * nop 622107071Stmm * nop 623107071Stmm * nop 624107071Stmm * nop 625107071Stmm * nop 626107071Stmm * 627107071Stmm */ 628107071Stmm where[1] = BAA | ((offset >> 2) &0x3fffff); 629107071Stmm flush(where, 4); 630107071Stmm } else if (target >= 0 && target < (1L<<32)) { 631115396Skan /* 632229780Suqs * We're within 32-bits of address zero. 633107071Stmm * 634107071Stmm * The resulting code in the jump slot is: 635107071Stmm * 636107071Stmm * sethi %hi(. - .PLT0), %g1 637107071Stmm * sethi %hi(addr), %g1 638107071Stmm * jmp %g1+%lo(addr) 639107071Stmm * nop 640107071Stmm * nop 641107071Stmm * nop 642107071Stmm * nop 643107071Stmm * nop 644107071Stmm * 645107071Stmm */ 646107071Stmm where[2] = JMP | LOVAL(target); 647107071Stmm flush(where, 8); 648107071Stmm where[1] = SETHI | HIVAL(target, 10); 649107071Stmm flush(where, 4); 650107071Stmm } else if (target <= 0 && target > -(1L<<32)) { 651115396Skan /* 652229780Suqs * We're within 32-bits of address -1. 653107071Stmm * 654107071Stmm * The resulting code in the jump slot is: 655107071Stmm * 656107071Stmm * sethi %hi(. - .PLT0), %g1 657107071Stmm * sethi %hix(addr), %g1 658107071Stmm * xor %g1, %lox(addr), %g1 659107071Stmm * jmp %g1 660107071Stmm * nop 661107071Stmm * nop 662107071Stmm * nop 663107071Stmm * nop 664107071Stmm * 665107071Stmm */ 666107071Stmm where[3] = JMP; 667107071Stmm flush(where, 12); 668107071Stmm where[2] = XOR | ((~target) & 0x00001fff); 669107071Stmm flush(where, 8); 670107071Stmm where[1] = SETHI | HIVAL(~target, 10); 671107071Stmm flush(where, 4); 672107071Stmm } else if (offset <= (1L<<32) && offset >= -((1L<<32) - 4)) { 673115396Skan /* 674229780Suqs * We're within 32-bits -- we can use a direct call 675107071Stmm * insn 676107071Stmm * 677107071Stmm * The resulting code in the jump slot is: 678107071Stmm * 679107071Stmm * sethi %hi(. - .PLT0), %g1 680107071Stmm * mov %o7, %g1 681107071Stmm * call (.+offset) 682107071Stmm * mov %g1, %o7 683107071Stmm * nop 684107071Stmm * nop 685107071Stmm * nop 686107071Stmm * nop 687107071Stmm * 688107071Stmm */ 689107071Stmm where[3] = MOV17; 690107071Stmm flush(where, 12); 691107071Stmm where[2] = CALL | ((offset >> 4) & 0x3fffffff); 692107071Stmm flush(where, 8); 693107071Stmm where[1] = MOV71; 694107071Stmm flush(where, 4); 695107071Stmm } else if (offset >= 0 && offset < (1L<<44)) { 696115396Skan /* 697229780Suqs * We're within 44 bits. We can generate this 698219532Smarius * pattern: 699107071Stmm * 700107071Stmm * The resulting code in the jump slot is: 701107071Stmm * 702107071Stmm * sethi %hi(. - .PLT0), %g1 703107071Stmm * sethi %h44(addr), %g1 704107071Stmm * or %g1, %m44(addr), %g1 705115396Skan * sllx %g1, 12, %g1 706115396Skan * jmp %g1+%l44(addr) 707107071Stmm * nop 708107071Stmm * nop 709107071Stmm * nop 710107071Stmm * 711107071Stmm */ 712107071Stmm where[4] = JMP | LOVAL(offset); 713107071Stmm flush(where, 16); 714107071Stmm where[3] = SLLX | 12; 715107071Stmm flush(where, 12); 716107071Stmm where[2] = OR | (((offset) >> 12) & 0x00001fff); 717107071Stmm flush(where, 8); 718107071Stmm where[1] = SETHI | HIVAL(offset, 22); 719107071Stmm flush(where, 4); 720107071Stmm } else if (offset < 0 && offset > -(1L<<44)) { 721115396Skan /* 722229780Suqs * We're within 44 bits. We can generate this 723219532Smarius * pattern: 724107071Stmm * 725107071Stmm * The resulting code in the jump slot is: 726107071Stmm * 727107071Stmm * sethi %hi(. - .PLT0), %g1 728107071Stmm * sethi %h44(-addr), %g1 729107071Stmm * xor %g1, %m44(-addr), %g1 730115396Skan * sllx %g1, 12, %g1 731115396Skan * jmp %g1+%l44(addr) 732107071Stmm * nop 733107071Stmm * nop 734107071Stmm * nop 735107071Stmm * 736107071Stmm */ 737107071Stmm where[4] = JMP | LOVAL(offset); 738107071Stmm flush(where, 16); 739107071Stmm where[3] = SLLX | 12; 740107071Stmm flush(where, 12); 741107071Stmm where[2] = XOR | (((~offset) >> 12) & 0x00001fff); 742107071Stmm flush(where, 8); 743107071Stmm where[1] = SETHI | HIVAL(~offset, 22); 744107071Stmm flush(where, 4); 745107071Stmm } else { 746115396Skan /* 747107071Stmm * We need to load all 64-bits 748107071Stmm * 749107071Stmm * The resulting code in the jump slot is: 750107071Stmm * 751107071Stmm * sethi %hi(. - .PLT0), %g1 752107071Stmm * sethi %hh(addr), %g1 753107071Stmm * sethi %lm(addr), %g5 754107071Stmm * or %g1, %hm(addr), %g1 755107071Stmm * sllx %g1, 32, %g1 756107071Stmm * or %g1, %g5, %g1 757107071Stmm * jmp %g1+%lo(addr) 758107071Stmm * nop 759107071Stmm * 760107071Stmm */ 761107071Stmm where[6] = JMP | LOVAL(target); 762107071Stmm flush(where, 24); 763107071Stmm where[5] = ORG5; 764107071Stmm flush(where, 20); 765146968Smarius where[4] = SLLX | 32; 766107071Stmm flush(where, 16); 767107071Stmm where[3] = OR | LOVAL((target) >> 32); 768107071Stmm flush(where, 12); 769107071Stmm where[2] = SETHIG5 | HIVAL(target, 10); 770107071Stmm flush(where, 8); 771107071Stmm where[1] = SETHI | HIVAL(target, 42); 772107071Stmm flush(where, 4); 773107071Stmm } 77492195Sjake } else { 775107071Stmm /* 776107071Stmm * This is a high PLT slot; the relocation offset specifies a 777107071Stmm * pointer that needs to be frobbed; no actual code needs to 778219532Smarius * be modified. The pointer to be calculated needs the addend 779107071Stmm * added and the reference object relocation base subtraced. 78092195Sjake */ 781107071Stmm *wherep = target + rela->r_addend - 782107071Stmm (Elf_Addr)refobj->relocbase; 78392195Sjake } 78492195Sjake 78592195Sjake return (target); 78692195Sjake} 78792195Sjake 788309061Skibvoid 789309061Skibifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 790309061Skib{ 791331206Smarius 792309061Skib} 793309061Skib 794331206Smariusextern void __sparc_utrap_setup(void); 795331206Smarius 796331206Smariusvoid 797331206Smariuspre_init(void) 798331206Smarius{ 799331206Smarius 800331206Smarius __sparc_utrap_setup(); 801331206Smarius} 802331206Smarius 80392195Sjake/* 80492195Sjake * Install rtld function call into this PLT slot. 80592195Sjake */ 80692195Sjake#define SAVE 0x9de3bf50 80792195Sjake#define SETHI_l0 0x21000000 80892195Sjake#define SETHI_l1 0x23000000 80992195Sjake#define OR_l0_l0 0xa0142000 81092195Sjake#define SLLX_l0_32_l0 0xa12c3020 81192195Sjake#define OR_l0_l1_l0 0xa0140011 81292195Sjake#define JMPL_l0_o1 0x93c42000 81392195Sjake#define MOV_g1_o0 0x90100001 81492195Sjake 81592195Sjakevoid 81692195Sjakeinit_pltgot(Obj_Entry *obj) 81792195Sjake{ 818153504Smarcel Elf_Word *entry; 81992195Sjake 82092195Sjake if (obj->pltgot != NULL) { 821153504Smarcel entry = (Elf_Word *)obj->pltgot; 82292195Sjake install_plt(&entry[0], (Elf_Addr)_rtld_bind_start_0); 82392195Sjake install_plt(&entry[8], (Elf_Addr)_rtld_bind_start_1); 82492195Sjake obj->pltgot[8] = (Elf_Addr)obj; 82592195Sjake } 82692195Sjake} 82792195Sjake 82892195Sjakestatic void 829153504Smarcelinstall_plt(Elf_Word *pltgot, Elf_Addr proc) 83092195Sjake{ 831331206Smarius 83292195Sjake pltgot[0] = SAVE; 83392195Sjake flush(pltgot, 0); 83492195Sjake pltgot[1] = SETHI_l0 | HIVAL(proc, 42); 83592195Sjake flush(pltgot, 4); 83692195Sjake pltgot[2] = SETHI_l1 | HIVAL(proc, 10); 83792195Sjake flush(pltgot, 8); 83892195Sjake pltgot[3] = OR_l0_l0 | LOVAL((proc) >> 32); 83992195Sjake flush(pltgot, 12); 84092195Sjake pltgot[4] = SLLX_l0_32_l0; 84192195Sjake flush(pltgot, 16); 84292195Sjake pltgot[5] = OR_l0_l1_l0; 84392195Sjake flush(pltgot, 20); 84492195Sjake pltgot[6] = JMPL_l0_o1 | LOVAL(proc); 84592195Sjake flush(pltgot, 24); 84692195Sjake pltgot[7] = MOV_g1_o0; 84792195Sjake flush(pltgot, 28); 84892195Sjake} 849133063Sdfr 850133063Sdfrvoid 851133063Sdfrallocate_initial_tls(Obj_Entry *objs) 852133063Sdfr{ 853219339Smarius Elf_Addr* tpval; 854133063Sdfr 855219339Smarius /* 856219339Smarius * Fix the size of the static TLS block by using the maximum offset 857219339Smarius * allocated so far and adding a bit for dynamic modules to use. 858219339Smarius */ 859219339Smarius tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; 860219339Smarius tpval = allocate_tls(objs, NULL, 3 * sizeof(Elf_Addr), 861219339Smarius sizeof(Elf_Addr)); 862219339Smarius __asm __volatile("mov %0, %%g7" : : "r" (tpval)); 863133063Sdfr} 864133063Sdfr 865133063Sdfrvoid *__tls_get_addr(tls_index *ti) 866133063Sdfr{ 867219339Smarius register Elf_Addr** tp __asm__("%g7"); 868133063Sdfr 869219339Smarius return (tls_get_addr_common(tp, ti->ti_module, ti->ti_offset)); 870133063Sdfr} 871