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$"); 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, 234233831Skib 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)); 267233831Skib req.flags = SYMLOOK_EARLY; 26892195Sjake 26992195Sjake for (srcobj = dstobj->next; srcobj != NULL; 270219339Smarius srcobj = srcobj->next) { 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 295233831Skibreloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 296233831Skib RtldLockState *lockstate) 29792195Sjake{ 29892195Sjake const Elf_Rela *relalim; 29992195Sjake const Elf_Rela *rela; 30092195Sjake SymCache *cache; 30198629Sdillon int r = -1; 30292195Sjake 30398629Sdillon /* 30498629Sdillon * The dynamic loader may be called from a thread, we have 30598629Sdillon * limited amounts of stack available so we cannot use alloca(). 30698629Sdillon */ 307171432Skensmith if (obj != obj_rtld) { 308235396Skib cache = calloc(obj->dynsymcount, sizeof(SymCache)); 309208256Srdivacky /* No need to check for NULL here */ 310171432Skensmith } else 31198629Sdillon cache = NULL; 31292195Sjake 31392195Sjake relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 31492195Sjake for (rela = obj->rela; rela < relalim; rela++) { 315233831Skib if (reloc_nonplt_object(obj, rela, cache, flags, lockstate) < 0) 31698629Sdillon goto done; 31792195Sjake } 31898629Sdillon r = 0; 31998629Sdillondone: 320208256Srdivacky if (cache != NULL) 321208256Srdivacky free(cache); 32298629Sdillon return (r); 32392195Sjake} 32492195Sjake 32592195Sjakestatic int 326216695Skibreloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache, 327233831Skib int flags, RtldLockState *lockstate) 32892195Sjake{ 32992195Sjake const Obj_Entry *defobj; 33092195Sjake const Elf_Sym *def; 33192195Sjake Elf_Addr *where; 332153504Smarcel Elf_Word *where32; 33392195Sjake Elf_Word type; 33492195Sjake Elf_Addr value; 33592195Sjake Elf_Addr mask; 336115396Skan 33792195Sjake where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 338153504Smarcel where32 = (Elf_Word *)where; 33992195Sjake defobj = NULL; 34092195Sjake def = NULL; 34192195Sjake 342172708Smarius type = ELF64_R_TYPE_ID(rela->r_info); 34392195Sjake if (type == R_SPARC_NONE) 34492195Sjake return (0); 34592195Sjake 346219339Smarius /* We do JMP_SLOTs below. */ 34792195Sjake if (type == R_SPARC_JMP_SLOT) 34892195Sjake return (0); 34992195Sjake 350219339Smarius /* COPY relocs are also handled elsewhere. */ 35192195Sjake if (type == R_SPARC_COPY) 35292195Sjake return (0); 35392195Sjake 354219533Smarius /* Ignore ADD and CALL relocations for dynamic TLS references. */ 355219533Smarius if (type == R_SPARC_TLS_GD_ADD || type == R_SPARC_TLS_GD_CALL || 356219533Smarius type == R_SPARC_TLS_LDM_ADD || type == R_SPARC_TLS_LDM_CALL || 357219533Smarius type == R_SPARC_TLS_LDO_ADD) 358219533Smarius return (0); 359219533Smarius 36092195Sjake /* 361219533Smarius * Note: R_SPARC_TLS_TPOFF64 must be the numerically largest 362219533Smarius * relocation type. 36392195Sjake */ 364172708Smarius if (type >= sizeof(reloc_target_bitmask) / 365219533Smarius sizeof(*reloc_target_bitmask)) { 366219533Smarius _rtld_error("%s: Unsupported relocation type %d in non-PLT " 367219533Smarius "object\n", obj->path, type); 36892195Sjake return (-1); 369219533Smarius } 37092195Sjake 37192195Sjake value = rela->r_addend; 37292195Sjake 37392195Sjake /* 374219339Smarius * Handle relative relocs here, because we might not be able to access 375219339Smarius * globals yet. 37692195Sjake */ 37792195Sjake if (type == R_SPARC_RELATIVE) { 378219339Smarius /* XXXX -- apparently we ignore the preexisting value. */ 37992195Sjake *where = (Elf_Addr)(obj->relocbase + value); 38092195Sjake return (0); 38192195Sjake } 38292195Sjake 38392195Sjake /* 38492195Sjake * If we get here while relocating rtld itself, we will crash because 38592195Sjake * a non-local variable is accessed. 38692195Sjake */ 38792195Sjake if (RELOC_RESOLVE_SYMBOL(type)) { 388219339Smarius /* Find the symbol. */ 38992195Sjake def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 390233831Skib flags, cache, lockstate); 39192195Sjake if (def == NULL) 39292195Sjake return (-1); 39392195Sjake 394219533Smarius if (RELOC_USE_TLS_ID(type)) 395219533Smarius value = (Elf_Addr)defobj->tlsindex; 396219533Smarius else if (RELOC_USE_TLS_DOFF(type)) 397219533Smarius value += (Elf_Addr)def->st_value; 398219533Smarius else if (RELOC_USE_TLS_OFF(type)) { 399219533Smarius /* 400219533Smarius * We lazily allocate offsets for static TLS as we 401219533Smarius * see the first relocation that references the TLS 402219533Smarius * block. This allows us to support (small amounts 403219533Smarius * of) static TLS in dynamically loaded modules. If 404219533Smarius * we run out of space, we generate an error. 405219533Smarius */ 406219533Smarius if (!defobj->tls_done && 407219533Smarius !allocate_tls_offset((Obj_Entry*)defobj)) { 408219533Smarius _rtld_error("%s: No space available for " 409219533Smarius "static Thread Local Storage", obj->path); 410219533Smarius return (-1); 411219533Smarius } 412219533Smarius value += (Elf_Addr)(def->st_value - 413219533Smarius defobj->tlsoffset); 414219533Smarius } else { 415219533Smarius /* Add in the symbol's absolute address. */ 416219533Smarius value += (Elf_Addr)(def->st_value + 417219533Smarius defobj->relocbase); 418219533Smarius } 41992195Sjake } 42092195Sjake 421172708Smarius if (type == R_SPARC_OLO10) 422172708Smarius value = (value & 0x3ff) + ELF64_R_TYPE_DATA(rela->r_info); 423172708Smarius 424219533Smarius if (type == R_SPARC_HIX22 || type == R_SPARC_TLS_LE_HIX22) 425219340Smarius value ^= 0xffffffffffffffff; 426219340Smarius 42792195Sjake if (RELOC_PC_RELATIVE(type)) 42892195Sjake value -= (Elf_Addr)where; 42992195Sjake 43092195Sjake if (RELOC_BASE_RELATIVE(type)) { 43192195Sjake /* 43292195Sjake * Note that even though sparcs use `Elf_rela' exclusively 43392195Sjake * we still need the implicit memory addend in relocations 434219532Smarius * referring to GOT entries. Undoubtedly, someone f*cked 43592195Sjake * this up in the distant past, and now we're stuck with 436219532Smarius * it in the name of compatibility for all eternity ... 43792195Sjake * 43892195Sjake * In any case, the implicit and explicit should be mutually 439219532Smarius * exclusive. We provide a check for that here. 44092195Sjake */ 44192195Sjake /* XXXX -- apparently we ignore the preexisting value */ 44292195Sjake value += (Elf_Addr)(obj->relocbase); 44392195Sjake } 44492195Sjake 44592195Sjake mask = RELOC_VALUE_BITMASK(type); 44692195Sjake value >>= RELOC_VALUE_RIGHTSHIFT(type); 44792195Sjake value &= mask; 44892195Sjake 449219533Smarius if (type == R_SPARC_LOX10 || type == R_SPARC_TLS_LE_LOX10) 450219533Smarius value |= 0x1c00; 451219533Smarius 45292195Sjake if (RELOC_UNALIGNED(type)) { 45392195Sjake /* Handle unaligned relocations. */ 45492195Sjake Elf_Addr tmp; 45592195Sjake char *ptr; 45692195Sjake int size; 45792195Sjake int i; 458115396Skan 45992195Sjake size = RELOC_TARGET_SIZE(type) / 8; 46092195Sjake ptr = (char *)where; 46192195Sjake tmp = 0; 462115396Skan 46392195Sjake /* Read it in one byte at a time. */ 46492195Sjake for (i = 0; i < size; i++) 46592195Sjake tmp = (tmp << 8) | ptr[i]; 46692195Sjake 46792195Sjake tmp &= ~mask; 46892195Sjake tmp |= value; 46992195Sjake 47092195Sjake /* Write it back out. */ 47192195Sjake for (i = 0; i < size; i++) 472107638Skan ptr[i] = ((tmp >> ((size - i - 1) * 8)) & 0xff); 47392195Sjake } else if (RELOC_TARGET_SIZE(type) > 32) { 47492195Sjake *where &= ~mask; 47592195Sjake *where |= value; 47692195Sjake } else { 47792195Sjake *where32 &= ~mask; 47892195Sjake *where32 |= value; 47992195Sjake } 48092195Sjake 48192195Sjake return (0); 48292195Sjake} 48392195Sjake 48492195Sjakeint 48592195Sjakereloc_plt(Obj_Entry *obj) 48692195Sjake{ 48792195Sjake#if 0 48892195Sjake const Obj_Entry *defobj; 48992195Sjake const Elf_Rela *relalim; 49092195Sjake const Elf_Rela *rela; 49192195Sjake const Elf_Sym *def; 49292195Sjake Elf_Addr *where; 49392195Sjake Elf_Addr value; 49492195Sjake 49592195Sjake relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 49692195Sjake for (rela = obj->pltrela; rela < relalim; rela++) { 49792195Sjake if (rela->r_addend == 0) 49892195Sjake continue; 499172708Smarius assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); 50092195Sjake where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 50192195Sjake def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 502216695Skib true, NULL, lockstate); 50392195Sjake value = (Elf_Addr)(defobj->relocbase + def->st_value); 50492195Sjake *where = value; 50592195Sjake } 50692195Sjake#endif 50792195Sjake return (0); 50892195Sjake} 50992195Sjake 51092195Sjake/* 51192195Sjake * Instruction templates: 51292195Sjake */ 51392195Sjake#define BAA 0x10400000 /* ba,a %xcc, 0 */ 51492195Sjake#define SETHI 0x03000000 /* sethi %hi(0), %g1 */ 51592195Sjake#define JMP 0x81c06000 /* jmpl %g1+%lo(0), %g0 */ 51692195Sjake#define NOP 0x01000000 /* sethi %hi(0), %g0 */ 51792195Sjake#define OR 0x82806000 /* or %g1, 0, %g1 */ 51892195Sjake#define XOR 0x82c06000 /* xor %g1, 0, %g1 */ 51992195Sjake#define MOV71 0x8283a000 /* or %o7, 0, %g1 */ 52092195Sjake#define MOV17 0x9c806000 /* or %g1, 0, %o7 */ 52192195Sjake#define CALL 0x40000000 /* call 0 */ 52292195Sjake#define SLLX 0x8b407000 /* sllx %g1, 0, %g1 */ 52392195Sjake#define SETHIG5 0x0b000000 /* sethi %hi(0), %g5 */ 52492195Sjake#define ORG5 0x82804005 /* or %g1, %g5, %g1 */ 52592195Sjake 52692195Sjake/* %hi(v) with variable shift */ 52792195Sjake#define HIVAL(v, s) (((v) >> (s)) & 0x003fffff) 528219532Smarius#define LOVAL(v) ((v) & 0x000003ff) 52992195Sjake 53092195Sjakeint 531233831Skibreloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 53292195Sjake{ 53392195Sjake const Obj_Entry *defobj; 53492195Sjake const Elf_Rela *relalim; 53592195Sjake const Elf_Rela *rela; 53692195Sjake const Elf_Sym *def; 53792195Sjake Elf_Addr *where; 53892195Sjake Elf_Addr target; 53992195Sjake 54092195Sjake relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 54192195Sjake for (rela = obj->pltrela; rela < relalim; rela++) { 542172708Smarius assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); 54392195Sjake where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 54492195Sjake def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 545233831Skib SYMLOOK_IN_PLT | flags, NULL, lockstate); 546103315Stmm if (def == NULL) 547103315Stmm return -1; 54892195Sjake target = (Elf_Addr)(defobj->relocbase + def->st_value); 549107071Stmm reloc_jmpslot(where, target, defobj, obj, (Elf_Rel *)rela); 55092195Sjake } 55192195Sjake obj->jmpslots_done = true; 55292195Sjake return (0); 55392195Sjake} 55492195Sjake 555229503Skibint 556229503Skibreloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 557229503Skib{ 558229503Skib 559229503Skib /* XXX not implemented */ 560229503Skib return (0); 561229503Skib} 562229503Skib 563229503Skibint 564233831Skibreloc_gnu_ifunc(Obj_Entry *obj, int flags, 565233831Skib struct Struct_RtldLockState *lockstate) 566229503Skib{ 567229503Skib 568229503Skib /* XXX not implemented */ 569229503Skib return (0); 570229503Skib} 571229503Skib 57292195SjakeElf_Addr 573107071Stmmreloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *obj, 574219339Smarius const Obj_Entry *refobj, const Elf_Rel *rel) 57592195Sjake{ 576107071Stmm const Elf_Rela *rela = (const Elf_Rela *)rel; 57792195Sjake Elf_Addr offset; 578153504Smarcel Elf_Word *where; 57992195Sjake 580107071Stmm if (rela - refobj->pltrela < 32764) { 581107071Stmm /* 582107071Stmm * At the PLT entry pointed at by `where', we now construct 583107071Stmm * a direct transfer to the now fully resolved function 584107071Stmm * address. 58592195Sjake * 586107071Stmm * A PLT entry is supposed to start by looking like this: 58792195Sjake * 588107071Stmm * sethi (. - .PLT0), %g1 589107071Stmm * ba,a %xcc, .PLT1 59092195Sjake * nop 59192195Sjake * nop 59292195Sjake * nop 59392195Sjake * nop 59492195Sjake * nop 59592195Sjake * nop 59692195Sjake * 597107071Stmm * When we replace these entries we start from the second 598107071Stmm * entry and do it in reverse order so the last thing we 599107071Stmm * do is replace the branch. That allows us to change this 600107071Stmm * atomically. 60192195Sjake * 602107071Stmm * We now need to find out how far we need to jump. We 603107071Stmm * have a choice of several different relocation techniques 604107071Stmm * which are increasingly expensive. 60592195Sjake */ 606153504Smarcel where = (Elf_Word *)wherep; 607107071Stmm offset = ((Elf_Addr)where) - target; 608107071Stmm if (offset <= (1L<<20) && offset >= -(1L<<20)) { 609115396Skan /* 610219532Smarius * We're within 1MB -- we can use a direct branch 611219532Smarius * instruction. 612107071Stmm * 613107071Stmm * We can generate this pattern: 614107071Stmm * 615107071Stmm * sethi %hi(. - .PLT0), %g1 616107071Stmm * ba,a %xcc, addr 617107071Stmm * nop 618107071Stmm * nop 619107071Stmm * nop 620107071Stmm * nop 621107071Stmm * nop 622107071Stmm * nop 623107071Stmm * 624107071Stmm */ 625107071Stmm where[1] = BAA | ((offset >> 2) &0x3fffff); 626107071Stmm flush(where, 4); 627107071Stmm } else if (target >= 0 && target < (1L<<32)) { 628115396Skan /* 629107071Stmm * We're withing 32-bits of address zero. 630107071Stmm * 631107071Stmm * The resulting code in the jump slot is: 632107071Stmm * 633107071Stmm * sethi %hi(. - .PLT0), %g1 634107071Stmm * sethi %hi(addr), %g1 635107071Stmm * jmp %g1+%lo(addr) 636107071Stmm * nop 637107071Stmm * nop 638107071Stmm * nop 639107071Stmm * nop 640107071Stmm * nop 641107071Stmm * 642107071Stmm */ 643107071Stmm where[2] = JMP | LOVAL(target); 644107071Stmm flush(where, 8); 645107071Stmm where[1] = SETHI | HIVAL(target, 10); 646107071Stmm flush(where, 4); 647107071Stmm } else if (target <= 0 && target > -(1L<<32)) { 648115396Skan /* 649107071Stmm * We're withing 32-bits of address -1. 650107071Stmm * 651107071Stmm * The resulting code in the jump slot is: 652107071Stmm * 653107071Stmm * sethi %hi(. - .PLT0), %g1 654107071Stmm * sethi %hix(addr), %g1 655107071Stmm * xor %g1, %lox(addr), %g1 656107071Stmm * jmp %g1 657107071Stmm * nop 658107071Stmm * nop 659107071Stmm * nop 660107071Stmm * nop 661107071Stmm * 662107071Stmm */ 663107071Stmm where[3] = JMP; 664107071Stmm flush(where, 12); 665107071Stmm where[2] = XOR | ((~target) & 0x00001fff); 666107071Stmm flush(where, 8); 667107071Stmm where[1] = SETHI | HIVAL(~target, 10); 668107071Stmm flush(where, 4); 669107071Stmm } else if (offset <= (1L<<32) && offset >= -((1L<<32) - 4)) { 670115396Skan /* 671107071Stmm * We're withing 32-bits -- we can use a direct call 672107071Stmm * insn 673107071Stmm * 674107071Stmm * The resulting code in the jump slot is: 675107071Stmm * 676107071Stmm * sethi %hi(. - .PLT0), %g1 677107071Stmm * mov %o7, %g1 678107071Stmm * call (.+offset) 679107071Stmm * mov %g1, %o7 680107071Stmm * nop 681107071Stmm * nop 682107071Stmm * nop 683107071Stmm * nop 684107071Stmm * 685107071Stmm */ 686107071Stmm where[3] = MOV17; 687107071Stmm flush(where, 12); 688107071Stmm where[2] = CALL | ((offset >> 4) & 0x3fffffff); 689107071Stmm flush(where, 8); 690107071Stmm where[1] = MOV71; 691107071Stmm flush(where, 4); 692107071Stmm } else if (offset >= 0 && offset < (1L<<44)) { 693115396Skan /* 694219532Smarius * We're withing 44 bits. We can generate this 695219532Smarius * pattern: 696107071Stmm * 697107071Stmm * The resulting code in the jump slot is: 698107071Stmm * 699107071Stmm * sethi %hi(. - .PLT0), %g1 700107071Stmm * sethi %h44(addr), %g1 701107071Stmm * or %g1, %m44(addr), %g1 702115396Skan * sllx %g1, 12, %g1 703115396Skan * jmp %g1+%l44(addr) 704107071Stmm * nop 705107071Stmm * nop 706107071Stmm * nop 707107071Stmm * 708107071Stmm */ 709107071Stmm where[4] = JMP | LOVAL(offset); 710107071Stmm flush(where, 16); 711107071Stmm where[3] = SLLX | 12; 712107071Stmm flush(where, 12); 713107071Stmm where[2] = OR | (((offset) >> 12) & 0x00001fff); 714107071Stmm flush(where, 8); 715107071Stmm where[1] = SETHI | HIVAL(offset, 22); 716107071Stmm flush(where, 4); 717107071Stmm } else if (offset < 0 && offset > -(1L<<44)) { 718115396Skan /* 719219532Smarius * We're withing 44 bits. We can generate this 720219532Smarius * pattern: 721107071Stmm * 722107071Stmm * The resulting code in the jump slot is: 723107071Stmm * 724107071Stmm * sethi %hi(. - .PLT0), %g1 725107071Stmm * sethi %h44(-addr), %g1 726107071Stmm * xor %g1, %m44(-addr), %g1 727115396Skan * sllx %g1, 12, %g1 728115396Skan * jmp %g1+%l44(addr) 729107071Stmm * nop 730107071Stmm * nop 731107071Stmm * nop 732107071Stmm * 733107071Stmm */ 734107071Stmm where[4] = JMP | LOVAL(offset); 735107071Stmm flush(where, 16); 736107071Stmm where[3] = SLLX | 12; 737107071Stmm flush(where, 12); 738107071Stmm where[2] = XOR | (((~offset) >> 12) & 0x00001fff); 739107071Stmm flush(where, 8); 740107071Stmm where[1] = SETHI | HIVAL(~offset, 22); 741107071Stmm flush(where, 4); 742107071Stmm } else { 743115396Skan /* 744107071Stmm * We need to load all 64-bits 745107071Stmm * 746107071Stmm * The resulting code in the jump slot is: 747107071Stmm * 748107071Stmm * sethi %hi(. - .PLT0), %g1 749107071Stmm * sethi %hh(addr), %g1 750107071Stmm * sethi %lm(addr), %g5 751107071Stmm * or %g1, %hm(addr), %g1 752107071Stmm * sllx %g1, 32, %g1 753107071Stmm * or %g1, %g5, %g1 754107071Stmm * jmp %g1+%lo(addr) 755107071Stmm * nop 756107071Stmm * 757107071Stmm */ 758107071Stmm where[6] = JMP | LOVAL(target); 759107071Stmm flush(where, 24); 760107071Stmm where[5] = ORG5; 761107071Stmm flush(where, 20); 762146968Smarius where[4] = SLLX | 32; 763107071Stmm flush(where, 16); 764107071Stmm where[3] = OR | LOVAL((target) >> 32); 765107071Stmm flush(where, 12); 766107071Stmm where[2] = SETHIG5 | HIVAL(target, 10); 767107071Stmm flush(where, 8); 768107071Stmm where[1] = SETHI | HIVAL(target, 42); 769107071Stmm flush(where, 4); 770107071Stmm } 77192195Sjake } else { 772107071Stmm /* 773107071Stmm * This is a high PLT slot; the relocation offset specifies a 774107071Stmm * pointer that needs to be frobbed; no actual code needs to 775219532Smarius * be modified. The pointer to be calculated needs the addend 776107071Stmm * added and the reference object relocation base subtraced. 77792195Sjake */ 778107071Stmm *wherep = target + rela->r_addend - 779107071Stmm (Elf_Addr)refobj->relocbase; 78092195Sjake } 78192195Sjake 78292195Sjake return (target); 78392195Sjake} 78492195Sjake 78592195Sjake/* 78692195Sjake * Install rtld function call into this PLT slot. 78792195Sjake */ 78892195Sjake#define SAVE 0x9de3bf50 78992195Sjake#define SETHI_l0 0x21000000 79092195Sjake#define SETHI_l1 0x23000000 79192195Sjake#define OR_l0_l0 0xa0142000 79292195Sjake#define SLLX_l0_32_l0 0xa12c3020 79392195Sjake#define OR_l0_l1_l0 0xa0140011 79492195Sjake#define JMPL_l0_o1 0x93c42000 79592195Sjake#define MOV_g1_o0 0x90100001 79692195Sjake 79792195Sjakevoid 79892195Sjakeinit_pltgot(Obj_Entry *obj) 79992195Sjake{ 800153504Smarcel Elf_Word *entry; 80192195Sjake 80292195Sjake if (obj->pltgot != NULL) { 803153504Smarcel entry = (Elf_Word *)obj->pltgot; 80492195Sjake install_plt(&entry[0], (Elf_Addr)_rtld_bind_start_0); 80592195Sjake install_plt(&entry[8], (Elf_Addr)_rtld_bind_start_1); 80692195Sjake obj->pltgot[8] = (Elf_Addr)obj; 80792195Sjake } 80892195Sjake} 80992195Sjake 81092195Sjakestatic void 811153504Smarcelinstall_plt(Elf_Word *pltgot, Elf_Addr proc) 81292195Sjake{ 81392195Sjake pltgot[0] = SAVE; 81492195Sjake flush(pltgot, 0); 81592195Sjake pltgot[1] = SETHI_l0 | HIVAL(proc, 42); 81692195Sjake flush(pltgot, 4); 81792195Sjake pltgot[2] = SETHI_l1 | HIVAL(proc, 10); 81892195Sjake flush(pltgot, 8); 81992195Sjake pltgot[3] = OR_l0_l0 | LOVAL((proc) >> 32); 82092195Sjake flush(pltgot, 12); 82192195Sjake pltgot[4] = SLLX_l0_32_l0; 82292195Sjake flush(pltgot, 16); 82392195Sjake pltgot[5] = OR_l0_l1_l0; 82492195Sjake flush(pltgot, 20); 82592195Sjake pltgot[6] = JMPL_l0_o1 | LOVAL(proc); 82692195Sjake flush(pltgot, 24); 82792195Sjake pltgot[7] = MOV_g1_o0; 82892195Sjake flush(pltgot, 28); 82992195Sjake} 830133063Sdfr 831133063Sdfrvoid 832133063Sdfrallocate_initial_tls(Obj_Entry *objs) 833133063Sdfr{ 834219339Smarius Elf_Addr* tpval; 835133063Sdfr 836219339Smarius /* 837219339Smarius * Fix the size of the static TLS block by using the maximum offset 838219339Smarius * allocated so far and adding a bit for dynamic modules to use. 839219339Smarius */ 840219339Smarius tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; 841219339Smarius tpval = allocate_tls(objs, NULL, 3 * sizeof(Elf_Addr), 842219339Smarius sizeof(Elf_Addr)); 843219339Smarius __asm __volatile("mov %0, %%g7" : : "r" (tpval)); 844133063Sdfr} 845133063Sdfr 846133063Sdfrvoid *__tls_get_addr(tls_index *ti) 847133063Sdfr{ 848219339Smarius register Elf_Addr** tp __asm__("%g7"); 849133063Sdfr 850219339Smarius return (tls_get_addr_common(tp, ti->ti_module, ti->ti_offset)); 851133063Sdfr} 852