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