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