xref: /titanic_50/usr/src/cmd/sgs/rtld/sparc/sparc_a.out.c (revision f441771b0ce9f9d6122d318ff8290cb1a2848f9d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  *	Copyright (c) 1988 AT&T
247257d1b4Sraf  *	All Rights Reserved
25*f441771bSRod Evans  *
26*f441771bSRod Evans  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
277257d1b4Sraf  */
287257d1b4Sraf 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * SPARC machine dependent and a.out format file class dependent functions.
317c478bd9Sstevel@tonic-gate  * Contains routines for performing function binding and symbol relocations.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include	<stdio.h>
357c478bd9Sstevel@tonic-gate #include	<sys/types.h>
367c478bd9Sstevel@tonic-gate #include	<sys/mman.h>
377c478bd9Sstevel@tonic-gate #include	<synch.h>
387c478bd9Sstevel@tonic-gate #include	<dlfcn.h>
395aefb655Srie #include	<debug.h>
407c478bd9Sstevel@tonic-gate #include	"_a.out.h"
417c478bd9Sstevel@tonic-gate #include	"_rtld.h"
427c478bd9Sstevel@tonic-gate #include	"_audit.h"
43*f441771bSRod Evans #include	"_inline_gen.h"
447c478bd9Sstevel@tonic-gate #include	"msg.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate extern void	iflush_range(caddr_t, size_t);
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * Function binding routine - invoked on the first call to a function through
507c478bd9Sstevel@tonic-gate  * the procedure linkage table;
517c478bd9Sstevel@tonic-gate  * passes first through an assembly language interface.
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * Takes the address of the PLT entry where the call originated,
547c478bd9Sstevel@tonic-gate  * the offset into the relocation table of the associated
557c478bd9Sstevel@tonic-gate  * relocation entry and the address of the link map (rt_private_map struct)
567c478bd9Sstevel@tonic-gate  * for the entry.
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  * Returns the address of the function referenced after re-writing the PLT
597c478bd9Sstevel@tonic-gate  * entry to invoke the function directly.
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * On error, causes process to terminate with a signal.
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate ulong_t
aout_bndr(caddr_t pc)647c478bd9Sstevel@tonic-gate aout_bndr(caddr_t pc)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	Rt_map		*lmp, *nlmp, *llmp;
677c478bd9Sstevel@tonic-gate 	struct relocation_info *rp;
687c478bd9Sstevel@tonic-gate 	struct nlist	*sp;
697c478bd9Sstevel@tonic-gate 	Sym		*sym;
707c478bd9Sstevel@tonic-gate 	char		*name;
717c478bd9Sstevel@tonic-gate 	int 		rndx, entry;
727c478bd9Sstevel@tonic-gate 	ulong_t		symval;
737c478bd9Sstevel@tonic-gate 	Slookup		sl;
7408278a5eSRod Evans 	Sresult		sr;
757c478bd9Sstevel@tonic-gate 	uint_t		binfo;
765aefb655Srie 	Lm_list		*lml;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	/*
797c478bd9Sstevel@tonic-gate 	 * For compatibility with libthread (TI_VERSION 1) we track the entry
807c478bd9Sstevel@tonic-gate 	 * value.  A zero value indicates we have recursed into ld.so.1 to
817c478bd9Sstevel@tonic-gate 	 * further process a locking request (see comments in completion()).
827c478bd9Sstevel@tonic-gate 	 * Under this recursion we disable tsort and cleanup activities.
837c478bd9Sstevel@tonic-gate 	 */
848cd45542Sraf 	entry = enter(0);
857c478bd9Sstevel@tonic-gate 
86cb511613SAli Bahrami 	for (lmp = lml_main.lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
8756deab07SRod Evans 		if (THIS_IS_AOUT(lmp)) {
887c478bd9Sstevel@tonic-gate 			if (pc > (caddr_t)(LM2LP(lmp)->lp_plt) &&
897c478bd9Sstevel@tonic-gate 			    pc < (caddr_t)((int)LM2LP(lmp)->lp_plt +
907c478bd9Sstevel@tonic-gate 			    AOUTDYN(lmp)->v2->ld_plt_sz))  {
917c478bd9Sstevel@tonic-gate 				break;
927c478bd9Sstevel@tonic-gate 			}
937c478bd9Sstevel@tonic-gate 		}
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #define	LAST22BITS	0x3fffff
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/* LINTED */
997c478bd9Sstevel@tonic-gate 	rndx = *(int *)(pc + (sizeof (ulong_t *) * 2)) & LAST22BITS;
1007c478bd9Sstevel@tonic-gate 	rp = &LM2LP(lmp)->lp_rp[rndx];
1017c478bd9Sstevel@tonic-gate 	sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum];
1027c478bd9Sstevel@tonic-gate 	name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	/*
1057c478bd9Sstevel@tonic-gate 	 * Determine the last link-map of this list, this'll be the starting
1067c478bd9Sstevel@tonic-gate 	 * point for any tsort() processing.
1077c478bd9Sstevel@tonic-gate 	 */
1085aefb655Srie 	lml = LIST(lmp);
1095aefb655Srie 	llmp = lml->lm_tail;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/*
11275e7992aSrie 	 * Find definition for symbol.  Initialize the symbol lookup data
11375e7992aSrie 	 * structure.
1147c478bd9Sstevel@tonic-gate 	 */
11575e7992aSrie 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, 0, 0, 0,
11675e7992aSrie 	    LKUP_DEFT);
11708278a5eSRod Evans 	SRESULT_INIT(sr, name);
1187c478bd9Sstevel@tonic-gate 
11908278a5eSRod Evans 	if (aout_lookup_sym(&sl, &sr, &binfo, NULL) == 0) {
1205aefb655Srie 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
1217c478bd9Sstevel@tonic-gate 		    demangle(name));
1225aefb655Srie 		rtldexit(lml, 1);
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
12508278a5eSRod Evans 	name = (char *)sr.sr_name;
12608278a5eSRod Evans 	nlmp = sr.sr_dmap;
12708278a5eSRod Evans 	sym = sr.sr_sym;
12808278a5eSRod Evans 
1297c478bd9Sstevel@tonic-gate 	symval = sym->st_value;
13008278a5eSRod Evans 
1317c478bd9Sstevel@tonic-gate 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
1327c478bd9Sstevel@tonic-gate 	    (sym->st_shndx != SHN_ABS))
1337c478bd9Sstevel@tonic-gate 		symval += (int)(ADDR(nlmp));
1347c478bd9Sstevel@tonic-gate 	if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) {
1357c478bd9Sstevel@tonic-gate 		/*
1367c478bd9Sstevel@tonic-gate 		 * Record that this new link map is now bound to the caller.
1377c478bd9Sstevel@tonic-gate 		 */
1387c478bd9Sstevel@tonic-gate 		if (bind_one(lmp, nlmp, BND_REFER) == 0)
1395aefb655Srie 			rtldexit(lml, 1);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/*
1437c478bd9Sstevel@tonic-gate 	 * Print binding information and rebuild PLT entry.
1447c478bd9Sstevel@tonic-gate 	 */
1455aefb655Srie 	DBG_CALL(Dbg_bind_global(lmp, (Addr)(ADDR(lmp) + rp->r_address),
1465aefb655Srie 	    (Off)rp->r_address, (Xword)(-1), PLT_T_NONE, nlmp,
1475aefb655Srie 	    (Addr)symval, sym->st_value, name, binfo));
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	if (!(rtld_flags & RT_FL_NOBIND))
1507c478bd9Sstevel@tonic-gate 		aout_plt_write((caddr_t)(ADDR(lmp) + rp->r_address), symval);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/*
1537c478bd9Sstevel@tonic-gate 	 * Complete any processing for newly loaded objects.  Note we don't
1547c478bd9Sstevel@tonic-gate 	 * know exactly where any new objects are loaded (we know the object
1557c478bd9Sstevel@tonic-gate 	 * that supplied the symbol, but others may have been loaded lazily as
1567c478bd9Sstevel@tonic-gate 	 * we searched for the symbol), so sorting starts from the last
1577c478bd9Sstevel@tonic-gate 	 * link-map know on entry to this routine.
1587c478bd9Sstevel@tonic-gate 	 */
1597c478bd9Sstevel@tonic-gate 	if (entry)
1607247f888Srie 		load_completion(llmp);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1637c478bd9Sstevel@tonic-gate 	 * Make sure the object to which we've bound has had it's .init fired.
1647c478bd9Sstevel@tonic-gate 	 * Cleanup before return to user code.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	if (entry) {
1677c478bd9Sstevel@tonic-gate 		is_dep_init(nlmp, lmp);
1688cd45542Sraf 		leave(lml, 0);
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	return (symval);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate #define	IS_PC_RELATIVE(X) (pc_rel_type[(X)] == 1)
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static const uchar_t pc_rel_type[] = {
1787c478bd9Sstevel@tonic-gate 	0,				/* RELOC_8 */
1797c478bd9Sstevel@tonic-gate 	0,				/* RELOC_16 */
1807c478bd9Sstevel@tonic-gate 	0,				/* RELOC_32 */
1817c478bd9Sstevel@tonic-gate 	1,				/* RELOC_DISP8 */
1827c478bd9Sstevel@tonic-gate 	1,				/* RELOC_DISP16 */
1837c478bd9Sstevel@tonic-gate 	1,				/* RELOC_DISP32 */
1847c478bd9Sstevel@tonic-gate 	1,				/* RELOC_WDISP30 */
1857c478bd9Sstevel@tonic-gate 	1,				/* RELOC_WDISP22 */
1867c478bd9Sstevel@tonic-gate 	0,				/* RELOC_HI22 */
1877c478bd9Sstevel@tonic-gate 	0,				/* RELOC_22 */
1887c478bd9Sstevel@tonic-gate 	0,				/* RELOC_13 */
1897c478bd9Sstevel@tonic-gate 	0,				/* RELOC_LO10 */
1907c478bd9Sstevel@tonic-gate 	0,				/* RELOC_SFA_BASE */
1917c478bd9Sstevel@tonic-gate 	0,				/* RELOC_SFA_OFF13 */
1927c478bd9Sstevel@tonic-gate 	0,				/* RELOC_BASE10 */
1937c478bd9Sstevel@tonic-gate 	0,				/* RELOC_BASE13 */
1947c478bd9Sstevel@tonic-gate 	0,				/* RELOC_BASE22 */
1957c478bd9Sstevel@tonic-gate 	0,				/* RELOC_PC10 */
1967c478bd9Sstevel@tonic-gate 	0,				/* RELOC_PC22 */
1977c478bd9Sstevel@tonic-gate 	0,				/* RELOC_JMP_TBL */
1987c478bd9Sstevel@tonic-gate 	0,				/* RELOC_SEGOFF16 */
1997c478bd9Sstevel@tonic-gate 	0,				/* RELOC_GLOB_DAT */
2007c478bd9Sstevel@tonic-gate 	0,				/* RELOC_JMP_SLOT */
2017c478bd9Sstevel@tonic-gate 	0				/* RELOC_RELATIVE */
2027c478bd9Sstevel@tonic-gate };
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate int
aout_reloc(Rt_map * lmp,uint_t plt,int * in_nfavl,APlist ** textrel)20556deab07SRod Evans aout_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	int		k;		/* loop temporary */
2087c478bd9Sstevel@tonic-gate 	int		nr;		/* number of relocations */
2097c478bd9Sstevel@tonic-gate 	char		*name;		/* symbol being searched for */
2107c478bd9Sstevel@tonic-gate 	long		value;		/* relocation temporary */
2117c478bd9Sstevel@tonic-gate 	long		*ra;		/* cached relocation address */
2127c478bd9Sstevel@tonic-gate 	struct relocation_info *rp;	/* current relocation */
2137c478bd9Sstevel@tonic-gate 	struct nlist	*sp;		/* symbol table of "symbol" */
2147c478bd9Sstevel@tonic-gate 	Rt_map *	_lmp;		/* lm which holds symbol definition */
2157c478bd9Sstevel@tonic-gate 	Sym *		sym;		/* symbol definition */
21656deab07SRod Evans 	int		ret = 1;
217cce0e03bSab196087 	APlist		*bound = NULL;
2185aefb655Srie 	Lm_list		*lml = LIST(lmp);
2197c478bd9Sstevel@tonic-gate 
2205aefb655Srie 	DBG_CALL(Dbg_reloc_run(lmp, SHT_RELA, plt, DBG_REL_START));
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * If we've been called upon to promote an RTLD_LAZY object to an
2247c478bd9Sstevel@tonic-gate 	 * RTLD_NOW don't bother to do anything - a.out's are bound as if
2257c478bd9Sstevel@tonic-gate 	 * RTLD_NOW regardless.
2267c478bd9Sstevel@tonic-gate 	 */
2277c478bd9Sstevel@tonic-gate 	if (plt)
2287c478bd9Sstevel@tonic-gate 		return (1);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	rp = LM2LP(lmp)->lp_rp;
2317c478bd9Sstevel@tonic-gate 	nr = GETRELSZ(AOUTDYN(lmp)) / sizeof (struct relocation_info);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * Initialize _PLT_, if any.
2357c478bd9Sstevel@tonic-gate 	 */
2367c478bd9Sstevel@tonic-gate 	if (AOUTDYN(lmp)->v2->ld_plt_sz)
2377c478bd9Sstevel@tonic-gate 		aout_plt_write((caddr_t)LM2LP(lmp)->lp_plt->jb_inst,
2387c478bd9Sstevel@tonic-gate 		    (ulong_t)aout_rtbndr);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/*
2417c478bd9Sstevel@tonic-gate 	 * Loop through relocations.
2427c478bd9Sstevel@tonic-gate 	 */
2437c478bd9Sstevel@tonic-gate 	for (k = 0; k < nr; k++, rp++) {
24456deab07SRod Evans 		mmapobj_result_t	*mpp;
24556deab07SRod Evans 
2467c478bd9Sstevel@tonic-gate 		/* LINTED */
2477c478bd9Sstevel@tonic-gate 		ra = (long *)&((char *)ADDR(lmp))[rp->r_address];
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		/*
25056deab07SRod Evans 		 * Make sure the segment is writable.
2517c478bd9Sstevel@tonic-gate 		 */
25256deab07SRod Evans 		if (((mpp = find_segment((caddr_t)ra, lmp)) != NULL) &&
25356deab07SRod Evans 		    ((mpp->mr_prot & PROT_WRITE) == 0)) {
25456deab07SRod Evans 			if ((set_prot(lmp, mpp, 1) == 0) ||
25556deab07SRod Evans 			    (aplist_append(textrel, mpp,
25656deab07SRod Evans 			    AL_CNT_TEXTREL) == NULL)) {
2577c478bd9Sstevel@tonic-gate 				ret = 0;
2587c478bd9Sstevel@tonic-gate 				break;
2597c478bd9Sstevel@tonic-gate 			}
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		/*
2637c478bd9Sstevel@tonic-gate 		 * Perform the relocation.
2647c478bd9Sstevel@tonic-gate 		 */
2657c478bd9Sstevel@tonic-gate 		if (rp->r_extern == 0) {
26608278a5eSRod Evans 			name = NULL;
2677c478bd9Sstevel@tonic-gate 			value = ADDR(lmp);
2687c478bd9Sstevel@tonic-gate 		} else {
2697c478bd9Sstevel@tonic-gate 			Slookup		sl;
27008278a5eSRod Evans 			Sresult		sr;
2717c478bd9Sstevel@tonic-gate 			uint_t		binfo;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 			if (rp->r_type == RELOC_JMP_SLOT)
2747c478bd9Sstevel@tonic-gate 				continue;
2757c478bd9Sstevel@tonic-gate 			sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum];
2767c478bd9Sstevel@tonic-gate 			name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 			/*
27975e7992aSrie 			 * Locate symbol.  Initialize the symbol lookup data
28075e7992aSrie 			 * structure.
2817c478bd9Sstevel@tonic-gate 			 */
28256deab07SRod Evans 			SLOOKUP_INIT(sl, name, lmp, 0, ld_entry_cnt,
28356deab07SRod Evans 			    0, 0, 0, 0, LKUP_STDRELOC);
28408278a5eSRod Evans 			SRESULT_INIT(sr, name);
2857c478bd9Sstevel@tonic-gate 
28608278a5eSRod Evans 			if (aout_lookup_sym(&sl, &sr, &binfo, in_nfavl) == 0) {
2875aefb655Srie 				if (lml->lm_flags & LML_FLG_TRC_WARN) {
2887c478bd9Sstevel@tonic-gate 					(void)
2897c478bd9Sstevel@tonic-gate 					    printf(MSG_INTL(MSG_LDD_SYM_NFOUND),
2907c478bd9Sstevel@tonic-gate 					    demangle(name), NAME(lmp));
2917c478bd9Sstevel@tonic-gate 					continue;
2927c478bd9Sstevel@tonic-gate 				} else {
2935aefb655Srie 					eprintf(lml, ERR_FATAL,
2947c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
2957c478bd9Sstevel@tonic-gate 					    demangle(name));
2967c478bd9Sstevel@tonic-gate 					ret = 0;
2977c478bd9Sstevel@tonic-gate 					break;
2987c478bd9Sstevel@tonic-gate 				}
2997c478bd9Sstevel@tonic-gate 			}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 			/*
3027c478bd9Sstevel@tonic-gate 			 * If symbol was found in an object other than the
3037c478bd9Sstevel@tonic-gate 			 * referencing object then record the binding.
3047c478bd9Sstevel@tonic-gate 			 */
30508278a5eSRod Evans 			name = (char *)sr.sr_name;
30608278a5eSRod Evans 			_lmp = sr.sr_dmap;
30708278a5eSRod Evans 			sym = sr.sr_sym;
30808278a5eSRod Evans 
3097c478bd9Sstevel@tonic-gate 			if ((lmp != _lmp) &&
3107c478bd9Sstevel@tonic-gate 			    ((FLAGS1(_lmp) & FL1_RT_NOINIFIN) == 0)) {
311cce0e03bSab196087 				if (aplist_test(&bound, _lmp,
3127c478bd9Sstevel@tonic-gate 				    AL_CNT_RELBIND) == 0) {
3137c478bd9Sstevel@tonic-gate 					ret = 0;
3147c478bd9Sstevel@tonic-gate 					break;
3157c478bd9Sstevel@tonic-gate 				}
3167c478bd9Sstevel@tonic-gate 			}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 			value = sym->st_value + rp->r_addend;
3197c478bd9Sstevel@tonic-gate 			if (!(FLAGS(_lmp) & FLG_RT_FIXED) &&
3207c478bd9Sstevel@tonic-gate 			    (sym->st_shndx != SHN_COMMON) &&
3217c478bd9Sstevel@tonic-gate 			    (sym->st_shndx != SHN_ABS))
3227c478bd9Sstevel@tonic-gate 				value += ADDR(_lmp);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			if (IS_PC_RELATIVE(rp->r_type))
3257c478bd9Sstevel@tonic-gate 				value -= (long)ADDR(lmp);
3267c478bd9Sstevel@tonic-gate 
3275aefb655Srie 			DBG_CALL(Dbg_bind_global(lmp, (Addr)ra,
3285aefb655Srie 			    (Off)(ra - ADDR(lmp)), (Xword)(-1), PLT_T_NONE,
3295aefb655Srie 			    _lmp, (Addr)value, sym->st_value, name, binfo));
3307c478bd9Sstevel@tonic-gate 		}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		/*
3337c478bd9Sstevel@tonic-gate 		 * Perform a specific relocation operation.
3347c478bd9Sstevel@tonic-gate 		 */
3357c478bd9Sstevel@tonic-gate 		switch (rp->r_type) {
3367c478bd9Sstevel@tonic-gate 		case RELOC_RELATIVE:
3377c478bd9Sstevel@tonic-gate 			value += *ra << (32-22);
3387c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
3397c478bd9Sstevel@tonic-gate 			    ((value >> (32 - 22)) & S_MASK(22));
3407c478bd9Sstevel@tonic-gate 			ra++;
3417c478bd9Sstevel@tonic-gate 			value += (*ra & S_MASK(10));
3427c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(10)) |
3437c478bd9Sstevel@tonic-gate 			    (value & S_MASK(10));
3447c478bd9Sstevel@tonic-gate 			break;
3457c478bd9Sstevel@tonic-gate 		case RELOC_8:
3467c478bd9Sstevel@tonic-gate 		case RELOC_DISP8:
3477c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(8);
3487247f888Srie 			if (!S_INRANGE(value, 8)) {
3497247f888Srie 				eprintf(lml, ERR_FATAL,
3507247f888Srie 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
3517247f888Srie 				    (name ? demangle(name) :
3527c478bd9Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 8,
3537c478bd9Sstevel@tonic-gate 				    (uint_t)ra);
3547247f888Srie 			}
3557c478bd9Sstevel@tonic-gate 			*ra = value;
3567c478bd9Sstevel@tonic-gate 			break;
3577c478bd9Sstevel@tonic-gate 		case RELOC_LO10:
3587c478bd9Sstevel@tonic-gate 		case RELOC_BASE10:
3597c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(10);
3607c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(10)) |
3617c478bd9Sstevel@tonic-gate 			    (value & S_MASK(10));
3627c478bd9Sstevel@tonic-gate 			break;
3637c478bd9Sstevel@tonic-gate 		case RELOC_BASE13:
3647c478bd9Sstevel@tonic-gate 		case RELOC_13:
3657c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(13);
3667c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(13)) |
3677c478bd9Sstevel@tonic-gate 			    (value & S_MASK(13));
3687c478bd9Sstevel@tonic-gate 			break;
3697c478bd9Sstevel@tonic-gate 		case RELOC_16:
3707c478bd9Sstevel@tonic-gate 		case RELOC_DISP16:
3717c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(16);
3727247f888Srie 			if (!S_INRANGE(value, 16)) {
3737247f888Srie 				eprintf(lml, ERR_FATAL,
3747247f888Srie 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
3757247f888Srie 				    (name ? demangle(name) :
3767c478bd9Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 16,
3777c478bd9Sstevel@tonic-gate 				    (uint_t)ra);
3787247f888Srie 			}
3797c478bd9Sstevel@tonic-gate 			*(short *)ra = value;
3807c478bd9Sstevel@tonic-gate 			break;
3817c478bd9Sstevel@tonic-gate 		case RELOC_22:
3827c478bd9Sstevel@tonic-gate 		case RELOC_BASE22:
3837c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(22);
3847247f888Srie 			if (!S_INRANGE(value, 22)) {
3857247f888Srie 				eprintf(lml, ERR_FATAL,
3867247f888Srie 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
3877247f888Srie 				    (name ? demangle(name) :
3887c478bd9Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22,
3897c478bd9Sstevel@tonic-gate 				    (uint_t)ra);
3907247f888Srie 			}
3917c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
3927c478bd9Sstevel@tonic-gate 			    (value & S_MASK(22));
3937c478bd9Sstevel@tonic-gate 			break;
3947c478bd9Sstevel@tonic-gate 		case RELOC_HI22:
3957c478bd9Sstevel@tonic-gate 			value += (*ra & S_MASK(22)) << (32 - 22);
3967c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
3977c478bd9Sstevel@tonic-gate 			    ((value >> (32 - 22)) & S_MASK(22));
3987c478bd9Sstevel@tonic-gate 			break;
3997c478bd9Sstevel@tonic-gate 		case RELOC_WDISP22:
4007c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(22);
4017c478bd9Sstevel@tonic-gate 			value >>= 2;
4027247f888Srie 			if (!S_INRANGE(value, 22)) {
4037247f888Srie 				eprintf(lml, ERR_FATAL,
4047247f888Srie 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
4057247f888Srie 				    (name ? demangle(name) :
4067c478bd9Sstevel@tonic-gate 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22,
4077c478bd9Sstevel@tonic-gate 				    (uint_t)ra);
4087247f888Srie 			}
4097c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
4107c478bd9Sstevel@tonic-gate 			    (value & S_MASK(22));
4117c478bd9Sstevel@tonic-gate 			break;
4127c478bd9Sstevel@tonic-gate 		case RELOC_WDISP30:
4137c478bd9Sstevel@tonic-gate 			value += *ra & S_MASK(30);
4147c478bd9Sstevel@tonic-gate 			value >>= 2;
4157c478bd9Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(30)) |
4167c478bd9Sstevel@tonic-gate 			    (value & S_MASK(30));
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		case RELOC_32:
4197c478bd9Sstevel@tonic-gate 		case RELOC_GLOB_DAT:
4207c478bd9Sstevel@tonic-gate 		case RELOC_DISP32:
4217c478bd9Sstevel@tonic-gate 			value += *ra;
4227c478bd9Sstevel@tonic-gate 			*(long *)ra = value;
4237c478bd9Sstevel@tonic-gate 			break;
4247c478bd9Sstevel@tonic-gate 		default:
4255aefb655Srie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNIMPL),
4265aefb655Srie 			    NAME(lmp), (name ? demangle(name) :
4275aefb655Srie 			    MSG_INTL(MSG_STR_UNKNOWN)), rp->r_type);
4287c478bd9Sstevel@tonic-gate 			ret = 0;
4297c478bd9Sstevel@tonic-gate 			break;
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 		/*
4337c478bd9Sstevel@tonic-gate 		 * If this relocation is against a text segment we must make
4347c478bd9Sstevel@tonic-gate 		 * sure that the instruction cache is flushed.
4357c478bd9Sstevel@tonic-gate 		 */
4367c478bd9Sstevel@tonic-gate 		if (textrel) {
4377c478bd9Sstevel@tonic-gate 			if (rp->r_type == RELOC_RELATIVE)
4387c478bd9Sstevel@tonic-gate 				iflush_range((caddr_t)(ra - 1), 0x8);
4397c478bd9Sstevel@tonic-gate 			else
4407c478bd9Sstevel@tonic-gate 				iflush_range((caddr_t)ra, 0x4);
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
44456deab07SRod Evans 	return (relocate_finish(lmp, bound, ret));
4457c478bd9Sstevel@tonic-gate }
446