xref: /onnv-gate/usr/src/cmd/sgs/rtld/sparc/sparc_a.out.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  *	Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
28*0Sstevel@tonic-gate /*	All Rights Reserved	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  * SPARC machine dependent and a.out format file class dependent functions.
34*0Sstevel@tonic-gate  * Contains routines for performing function binding and symbol relocations.
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate #include	"_synonyms.h"
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include	<stdio.h>
39*0Sstevel@tonic-gate #include	<sys/types.h>
40*0Sstevel@tonic-gate #include	<sys/mman.h>
41*0Sstevel@tonic-gate #include	<synch.h>
42*0Sstevel@tonic-gate #include	<dlfcn.h>
43*0Sstevel@tonic-gate #include	"_a.out.h"
44*0Sstevel@tonic-gate #include	"_rtld.h"
45*0Sstevel@tonic-gate #include	"_audit.h"
46*0Sstevel@tonic-gate #include	"msg.h"
47*0Sstevel@tonic-gate #include	"debug.h"
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate extern void	iflush_range(caddr_t, size_t);
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /*
52*0Sstevel@tonic-gate  * Function binding routine - invoked on the first call to a function through
53*0Sstevel@tonic-gate  * the procedure linkage table;
54*0Sstevel@tonic-gate  * passes first through an assembly language interface.
55*0Sstevel@tonic-gate  *
56*0Sstevel@tonic-gate  * Takes the address of the PLT entry where the call originated,
57*0Sstevel@tonic-gate  * the offset into the relocation table of the associated
58*0Sstevel@tonic-gate  * relocation entry and the address of the link map (rt_private_map struct)
59*0Sstevel@tonic-gate  * for the entry.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * Returns the address of the function referenced after re-writing the PLT
62*0Sstevel@tonic-gate  * entry to invoke the function directly.
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  * On error, causes process to terminate with a signal.
65*0Sstevel@tonic-gate  */
66*0Sstevel@tonic-gate ulong_t
67*0Sstevel@tonic-gate aout_bndr(caddr_t pc)
68*0Sstevel@tonic-gate {
69*0Sstevel@tonic-gate 	Rt_map *	lmp, * nlmp, * llmp;
70*0Sstevel@tonic-gate 	struct relocation_info *rp;
71*0Sstevel@tonic-gate 	struct nlist	*sp;
72*0Sstevel@tonic-gate 	Sym *		sym;
73*0Sstevel@tonic-gate 	char		*name;
74*0Sstevel@tonic-gate 	int 		rndx, entry;
75*0Sstevel@tonic-gate 	ulong_t		symval;
76*0Sstevel@tonic-gate 	Slookup		sl;
77*0Sstevel@tonic-gate 	uint_t		binfo;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	/*
80*0Sstevel@tonic-gate 	 * For compatibility with libthread (TI_VERSION 1) we track the entry
81*0Sstevel@tonic-gate 	 * value.  A zero value indicates we have recursed into ld.so.1 to
82*0Sstevel@tonic-gate 	 * further process a locking request (see comments in completion()).
83*0Sstevel@tonic-gate 	 * Under this recursion we disable tsort and cleanup activities.
84*0Sstevel@tonic-gate 	 */
85*0Sstevel@tonic-gate 	entry = enter();
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	for (lmp = lml_main.lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) {
88*0Sstevel@tonic-gate 		if (FCT(lmp) == &aout_fct) {
89*0Sstevel@tonic-gate 			if (pc > (caddr_t)(LM2LP(lmp)->lp_plt) &&
90*0Sstevel@tonic-gate 			    pc < (caddr_t)((int)LM2LP(lmp)->lp_plt +
91*0Sstevel@tonic-gate 			    AOUTDYN(lmp)->v2->ld_plt_sz))  {
92*0Sstevel@tonic-gate 				break;
93*0Sstevel@tonic-gate 			}
94*0Sstevel@tonic-gate 		}
95*0Sstevel@tonic-gate 	}
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate #define	LAST22BITS	0x3fffff
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	/* LINTED */
100*0Sstevel@tonic-gate 	rndx = *(int *)(pc + (sizeof (ulong_t *) * 2)) & LAST22BITS;
101*0Sstevel@tonic-gate 	rp = &LM2LP(lmp)->lp_rp[rndx];
102*0Sstevel@tonic-gate 	sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum];
103*0Sstevel@tonic-gate 	name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	/*
106*0Sstevel@tonic-gate 	 * Determine the last link-map of this list, this'll be the starting
107*0Sstevel@tonic-gate 	 * point for any tsort() processing.
108*0Sstevel@tonic-gate 	 */
109*0Sstevel@tonic-gate 	llmp = LIST(lmp)->lm_tail;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	/*
112*0Sstevel@tonic-gate 	 * Find definition for symbol.
113*0Sstevel@tonic-gate 	 */
114*0Sstevel@tonic-gate 	sl.sl_name = name;
115*0Sstevel@tonic-gate 	sl.sl_cmap = lmp;
116*0Sstevel@tonic-gate 	sl.sl_imap = LIST(lmp)->lm_head;
117*0Sstevel@tonic-gate 	sl.sl_hash = 0;
118*0Sstevel@tonic-gate 	sl.sl_rsymndx = 0;
119*0Sstevel@tonic-gate 	sl.sl_flags = LKUP_DEFT;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	if ((sym = aout_lookup_sym(&sl, &nlmp, &binfo)) == 0) {
122*0Sstevel@tonic-gate 		eprintf(ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
123*0Sstevel@tonic-gate 		    demangle(name));
124*0Sstevel@tonic-gate 		rtldexit(LIST(lmp), 1);
125*0Sstevel@tonic-gate 	}
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	symval = sym->st_value;
128*0Sstevel@tonic-gate 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
129*0Sstevel@tonic-gate 	    (sym->st_shndx != SHN_ABS))
130*0Sstevel@tonic-gate 		symval += (int)(ADDR(nlmp));
131*0Sstevel@tonic-gate 	if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) {
132*0Sstevel@tonic-gate 		/*
133*0Sstevel@tonic-gate 		 * Record that this new link map is now bound to the caller.
134*0Sstevel@tonic-gate 		 */
135*0Sstevel@tonic-gate 		if (bind_one(lmp, nlmp, BND_REFER) == 0)
136*0Sstevel@tonic-gate 			rtldexit(LIST(lmp), 1);
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	/*
140*0Sstevel@tonic-gate 	 * Print binding information and rebuild PLT entry.
141*0Sstevel@tonic-gate 	 */
142*0Sstevel@tonic-gate 	DBG_CALL(Dbg_bind_global(NAME(lmp),
143*0Sstevel@tonic-gate 	    (caddr_t)(ADDR(lmp) + rp->r_address), (caddr_t)rp->r_address,
144*0Sstevel@tonic-gate 	    (Xword)(-1), PLT_T_NONE, NAME(nlmp), (caddr_t)symval,
145*0Sstevel@tonic-gate 	    (caddr_t)sym->st_value, name, binfo));
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	if (!(rtld_flags & RT_FL_NOBIND))
148*0Sstevel@tonic-gate 		aout_plt_write((caddr_t)(ADDR(lmp) + rp->r_address), symval);
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	/*
151*0Sstevel@tonic-gate 	 * Complete any processing for newly loaded objects.  Note we don't
152*0Sstevel@tonic-gate 	 * know exactly where any new objects are loaded (we know the object
153*0Sstevel@tonic-gate 	 * that supplied the symbol, but others may have been loaded lazily as
154*0Sstevel@tonic-gate 	 * we searched for the symbol), so sorting starts from the last
155*0Sstevel@tonic-gate 	 * link-map know on entry to this routine.
156*0Sstevel@tonic-gate 	 */
157*0Sstevel@tonic-gate 	if (entry)
158*0Sstevel@tonic-gate 		load_completion(llmp, lmp);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	/*
161*0Sstevel@tonic-gate 	 * If the object we've bound to is in the process of being initialized
162*0Sstevel@tonic-gate 	 * by another thread, determine whether we should block.
163*0Sstevel@tonic-gate 	 */
164*0Sstevel@tonic-gate 	is_dep_ready(nlmp, lmp, DBG_WAIT_SYMBOL);
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	/*
167*0Sstevel@tonic-gate 	 * Make sure the object to which we've bound has had it's .init fired.
168*0Sstevel@tonic-gate 	 * Cleanup before return to user code.
169*0Sstevel@tonic-gate 	 */
170*0Sstevel@tonic-gate 	if (entry) {
171*0Sstevel@tonic-gate 		is_dep_init(nlmp, lmp);
172*0Sstevel@tonic-gate 		leave(LIST(lmp));
173*0Sstevel@tonic-gate 	}
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	return (symval);
176*0Sstevel@tonic-gate }
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate #define	IS_PC_RELATIVE(X) (pc_rel_type[(X)] == 1)
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate static const uchar_t pc_rel_type[] = {
182*0Sstevel@tonic-gate 	0,				/* RELOC_8 */
183*0Sstevel@tonic-gate 	0,				/* RELOC_16 */
184*0Sstevel@tonic-gate 	0,				/* RELOC_32 */
185*0Sstevel@tonic-gate 	1,				/* RELOC_DISP8 */
186*0Sstevel@tonic-gate 	1,				/* RELOC_DISP16 */
187*0Sstevel@tonic-gate 	1,				/* RELOC_DISP32 */
188*0Sstevel@tonic-gate 	1,				/* RELOC_WDISP30 */
189*0Sstevel@tonic-gate 	1,				/* RELOC_WDISP22 */
190*0Sstevel@tonic-gate 	0,				/* RELOC_HI22 */
191*0Sstevel@tonic-gate 	0,				/* RELOC_22 */
192*0Sstevel@tonic-gate 	0,				/* RELOC_13 */
193*0Sstevel@tonic-gate 	0,				/* RELOC_LO10 */
194*0Sstevel@tonic-gate 	0,				/* RELOC_SFA_BASE */
195*0Sstevel@tonic-gate 	0,				/* RELOC_SFA_OFF13 */
196*0Sstevel@tonic-gate 	0,				/* RELOC_BASE10 */
197*0Sstevel@tonic-gate 	0,				/* RELOC_BASE13 */
198*0Sstevel@tonic-gate 	0,				/* RELOC_BASE22 */
199*0Sstevel@tonic-gate 	0,				/* RELOC_PC10 */
200*0Sstevel@tonic-gate 	0,				/* RELOC_PC22 */
201*0Sstevel@tonic-gate 	0,				/* RELOC_JMP_TBL */
202*0Sstevel@tonic-gate 	0,				/* RELOC_SEGOFF16 */
203*0Sstevel@tonic-gate 	0,				/* RELOC_GLOB_DAT */
204*0Sstevel@tonic-gate 	0,				/* RELOC_JMP_SLOT */
205*0Sstevel@tonic-gate 	0				/* RELOC_RELATIVE */
206*0Sstevel@tonic-gate };
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate int
209*0Sstevel@tonic-gate aout_reloc(Rt_map * lmp, uint_t plt)
210*0Sstevel@tonic-gate {
211*0Sstevel@tonic-gate 	int		k;		/* loop temporary */
212*0Sstevel@tonic-gate 	int		nr;		/* number of relocations */
213*0Sstevel@tonic-gate 	char		*name;		/* symbol being searched for */
214*0Sstevel@tonic-gate 	long		*et;		/* cached _etext of object */
215*0Sstevel@tonic-gate 	long		value;		/* relocation temporary */
216*0Sstevel@tonic-gate 	long		*ra;		/* cached relocation address */
217*0Sstevel@tonic-gate 	struct relocation_info *rp;	/* current relocation */
218*0Sstevel@tonic-gate 	struct nlist	*sp;		/* symbol table of "symbol" */
219*0Sstevel@tonic-gate 	Rt_map *	_lmp;		/* lm which holds symbol definition */
220*0Sstevel@tonic-gate 	Sym *		sym;		/* symbol definition */
221*0Sstevel@tonic-gate 	int		textrel = 0, ret = 1;
222*0Sstevel@tonic-gate 	Alist		*bound = 0;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	DBG_CALL(Dbg_reloc_run(NAME(lmp), SHT_RELA, plt, DBG_REL_START));
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	/*
227*0Sstevel@tonic-gate 	 * If we've been called upon to promote an RTLD_LAZY object to an
228*0Sstevel@tonic-gate 	 * RTLD_NOW don't bother to do anything - a.out's are bound as if
229*0Sstevel@tonic-gate 	 * RTLD_NOW regardless.
230*0Sstevel@tonic-gate 	 */
231*0Sstevel@tonic-gate 	if (plt)
232*0Sstevel@tonic-gate 		return (1);
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	rp = LM2LP(lmp)->lp_rp;
235*0Sstevel@tonic-gate 	et = (long *)ETEXT(lmp);
236*0Sstevel@tonic-gate 	nr = GETRELSZ(AOUTDYN(lmp)) / sizeof (struct relocation_info);
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	/*
239*0Sstevel@tonic-gate 	 * Initialize _PLT_, if any.
240*0Sstevel@tonic-gate 	 */
241*0Sstevel@tonic-gate 	if (AOUTDYN(lmp)->v2->ld_plt_sz)
242*0Sstevel@tonic-gate 		aout_plt_write((caddr_t)LM2LP(lmp)->lp_plt->jb_inst,
243*0Sstevel@tonic-gate 		    (ulong_t)aout_rtbndr);
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	/*
246*0Sstevel@tonic-gate 	 * Loop through relocations.
247*0Sstevel@tonic-gate 	 */
248*0Sstevel@tonic-gate 	for (k = 0; k < nr; k++, rp++) {
249*0Sstevel@tonic-gate 		/* LINTED */
250*0Sstevel@tonic-gate 		ra = (long *)&((char *)ADDR(lmp))[rp->r_address];
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 		/*
253*0Sstevel@tonic-gate 		 * Check to see if we're relocating in the text segment
254*0Sstevel@tonic-gate 		 * and turn off the write protect if necessary.
255*0Sstevel@tonic-gate 		 */
256*0Sstevel@tonic-gate 		if ((ra < et) && (textrel == 0)) {
257*0Sstevel@tonic-gate 			if (aout_set_prot(lmp, PROT_WRITE) == 0) {
258*0Sstevel@tonic-gate 				ret = 0;
259*0Sstevel@tonic-gate 				break;
260*0Sstevel@tonic-gate 			}
261*0Sstevel@tonic-gate 			textrel = 1;
262*0Sstevel@tonic-gate 		}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 		/*
265*0Sstevel@tonic-gate 		 * Perform the relocation.
266*0Sstevel@tonic-gate 		 */
267*0Sstevel@tonic-gate 		if (rp->r_extern == 0) {
268*0Sstevel@tonic-gate 			name = (char *)0;
269*0Sstevel@tonic-gate 			value = ADDR(lmp);
270*0Sstevel@tonic-gate 		} else {
271*0Sstevel@tonic-gate 			Slookup		sl;
272*0Sstevel@tonic-gate 			uint_t		binfo;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 			if (rp->r_type == RELOC_JMP_SLOT)
275*0Sstevel@tonic-gate 				continue;
276*0Sstevel@tonic-gate 			sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum];
277*0Sstevel@tonic-gate 			name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 			/*
280*0Sstevel@tonic-gate 			 * Locate symbol.
281*0Sstevel@tonic-gate 			 */
282*0Sstevel@tonic-gate 			sl.sl_name = name;
283*0Sstevel@tonic-gate 			sl.sl_cmap = lmp;
284*0Sstevel@tonic-gate 			sl.sl_imap = 0;
285*0Sstevel@tonic-gate 			sl.sl_hash = 0;
286*0Sstevel@tonic-gate 			sl.sl_rsymndx = 0;
287*0Sstevel@tonic-gate 			sl.sl_flags = (LKUP_DEFT | LKUP_ALLCNTLIST);
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 			if ((sym = aout_lookup_sym(&sl, &_lmp, &binfo)) == 0) {
290*0Sstevel@tonic-gate 				if (LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) {
291*0Sstevel@tonic-gate 					(void)
292*0Sstevel@tonic-gate 					    printf(MSG_INTL(MSG_LDD_SYM_NFOUND),
293*0Sstevel@tonic-gate 					    demangle(name), NAME(lmp));
294*0Sstevel@tonic-gate 					continue;
295*0Sstevel@tonic-gate 				} else {
296*0Sstevel@tonic-gate 					eprintf(ERR_FATAL,
297*0Sstevel@tonic-gate 					    MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
298*0Sstevel@tonic-gate 					    demangle(name));
299*0Sstevel@tonic-gate 					ret = 0;
300*0Sstevel@tonic-gate 					break;
301*0Sstevel@tonic-gate 				}
302*0Sstevel@tonic-gate 			}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 			/*
305*0Sstevel@tonic-gate 			 * If symbol was found in an object other than the
306*0Sstevel@tonic-gate 			 * referencing object then record the binding.
307*0Sstevel@tonic-gate 			 */
308*0Sstevel@tonic-gate 			if ((lmp != _lmp) &&
309*0Sstevel@tonic-gate 			    ((FLAGS1(_lmp) & FL1_RT_NOINIFIN) == 0)) {
310*0Sstevel@tonic-gate 				if (alist_test(&bound, _lmp, sizeof (Rt_map *),
311*0Sstevel@tonic-gate 				    AL_CNT_RELBIND) == 0) {
312*0Sstevel@tonic-gate 					ret = 0;
313*0Sstevel@tonic-gate 					break;
314*0Sstevel@tonic-gate 				}
315*0Sstevel@tonic-gate 			}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 			value = sym->st_value + rp->r_addend;
318*0Sstevel@tonic-gate 			if (!(FLAGS(_lmp) & FLG_RT_FIXED) &&
319*0Sstevel@tonic-gate 			    (sym->st_shndx != SHN_COMMON) &&
320*0Sstevel@tonic-gate 			    (sym->st_shndx != SHN_ABS))
321*0Sstevel@tonic-gate 				value += ADDR(_lmp);
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 			if (IS_PC_RELATIVE(rp->r_type))
324*0Sstevel@tonic-gate 				value -= (long)ADDR(lmp);
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 			DBG_CALL(Dbg_bind_global(NAME(lmp), (caddr_t)ra,
327*0Sstevel@tonic-gate 			    (caddr_t)(ra - ADDR(lmp)), (Xword)(-1), PLT_T_NONE,
328*0Sstevel@tonic-gate 			    NAME(_lmp), (caddr_t)value, (caddr_t)sym->st_value,
329*0Sstevel@tonic-gate 			    name, binfo));
330*0Sstevel@tonic-gate 		}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 		/*
333*0Sstevel@tonic-gate 		 * Perform a specific relocation operation.
334*0Sstevel@tonic-gate 		 */
335*0Sstevel@tonic-gate 		switch (rp->r_type) {
336*0Sstevel@tonic-gate 		case RELOC_RELATIVE:
337*0Sstevel@tonic-gate 			value += *ra << (32-22);
338*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
339*0Sstevel@tonic-gate 				((value >> (32 - 22)) & S_MASK(22));
340*0Sstevel@tonic-gate 			ra++;
341*0Sstevel@tonic-gate 			value += (*ra & S_MASK(10));
342*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(10)) |
343*0Sstevel@tonic-gate 				(value & S_MASK(10));
344*0Sstevel@tonic-gate 			break;
345*0Sstevel@tonic-gate 		case RELOC_8:
346*0Sstevel@tonic-gate 		case RELOC_DISP8:
347*0Sstevel@tonic-gate 			value += *ra & S_MASK(8);
348*0Sstevel@tonic-gate 			if (!S_INRANGE(value, 8))
349*0Sstevel@tonic-gate 			    eprintf(ERR_FATAL, MSG_INTL(MSG_REL_OVERFLOW),
350*0Sstevel@tonic-gate 				NAME(lmp), (name ? demangle(name) :
351*0Sstevel@tonic-gate 				MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 8,
352*0Sstevel@tonic-gate 				(uint_t)ra);
353*0Sstevel@tonic-gate 			*ra = value;
354*0Sstevel@tonic-gate 			break;
355*0Sstevel@tonic-gate 		case RELOC_LO10:
356*0Sstevel@tonic-gate 		case RELOC_BASE10:
357*0Sstevel@tonic-gate 			value += *ra & S_MASK(10);
358*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(10)) |
359*0Sstevel@tonic-gate 				(value & S_MASK(10));
360*0Sstevel@tonic-gate 			break;
361*0Sstevel@tonic-gate 		case RELOC_BASE13:
362*0Sstevel@tonic-gate 		case RELOC_13:
363*0Sstevel@tonic-gate 			value += *ra & S_MASK(13);
364*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(13)) |
365*0Sstevel@tonic-gate 				(value & S_MASK(13));
366*0Sstevel@tonic-gate 			break;
367*0Sstevel@tonic-gate 		case RELOC_16:
368*0Sstevel@tonic-gate 		case RELOC_DISP16:
369*0Sstevel@tonic-gate 			value += *ra & S_MASK(16);
370*0Sstevel@tonic-gate 			if (!S_INRANGE(value, 16))
371*0Sstevel@tonic-gate 			    eprintf(ERR_FATAL, MSG_INTL(MSG_REL_OVERFLOW),
372*0Sstevel@tonic-gate 				NAME(lmp), (name ? demangle(name) :
373*0Sstevel@tonic-gate 				MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 16,
374*0Sstevel@tonic-gate 				(uint_t)ra);
375*0Sstevel@tonic-gate 			*(short *)ra = value;
376*0Sstevel@tonic-gate 			break;
377*0Sstevel@tonic-gate 		case RELOC_22:
378*0Sstevel@tonic-gate 		case RELOC_BASE22:
379*0Sstevel@tonic-gate 			value += *ra & S_MASK(22);
380*0Sstevel@tonic-gate 			if (!S_INRANGE(value, 22))
381*0Sstevel@tonic-gate 			    eprintf(ERR_FATAL, MSG_INTL(MSG_REL_OVERFLOW),
382*0Sstevel@tonic-gate 				NAME(lmp), (name ? demangle(name) :
383*0Sstevel@tonic-gate 				MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22,
384*0Sstevel@tonic-gate 				(uint_t)ra);
385*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
386*0Sstevel@tonic-gate 				(value & S_MASK(22));
387*0Sstevel@tonic-gate 			break;
388*0Sstevel@tonic-gate 		case RELOC_HI22:
389*0Sstevel@tonic-gate 			value += (*ra & S_MASK(22)) << (32 - 22);
390*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
391*0Sstevel@tonic-gate 				((value >> (32 - 22)) & S_MASK(22));
392*0Sstevel@tonic-gate 			break;
393*0Sstevel@tonic-gate 		case RELOC_WDISP22:
394*0Sstevel@tonic-gate 			value += *ra & S_MASK(22);
395*0Sstevel@tonic-gate 			value >>= 2;
396*0Sstevel@tonic-gate 			if (!S_INRANGE(value, 22))
397*0Sstevel@tonic-gate 			    eprintf(ERR_FATAL, MSG_INTL(MSG_REL_OVERFLOW),
398*0Sstevel@tonic-gate 				NAME(lmp), (name ? demangle(name) :
399*0Sstevel@tonic-gate 				MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22,
400*0Sstevel@tonic-gate 				(uint_t)ra);
401*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
402*0Sstevel@tonic-gate 				(value & S_MASK(22));
403*0Sstevel@tonic-gate 			break;
404*0Sstevel@tonic-gate 		case RELOC_WDISP30:
405*0Sstevel@tonic-gate 			value += *ra & S_MASK(30);
406*0Sstevel@tonic-gate 			value >>= 2;
407*0Sstevel@tonic-gate 			*(long *)ra = (*(long *)ra & ~S_MASK(30)) |
408*0Sstevel@tonic-gate 				(value & S_MASK(30));
409*0Sstevel@tonic-gate 			break;
410*0Sstevel@tonic-gate 		case RELOC_32:
411*0Sstevel@tonic-gate 		case RELOC_GLOB_DAT:
412*0Sstevel@tonic-gate 		case RELOC_DISP32:
413*0Sstevel@tonic-gate 			value += *ra;
414*0Sstevel@tonic-gate 			*(long *)ra = value;
415*0Sstevel@tonic-gate 			break;
416*0Sstevel@tonic-gate 		default:
417*0Sstevel@tonic-gate 			eprintf(ERR_FATAL, MSG_INTL(MSG_REL_UNIMPL), NAME(lmp),
418*0Sstevel@tonic-gate 			    (name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)),
419*0Sstevel@tonic-gate 			    rp->r_type);
420*0Sstevel@tonic-gate 			ret = 0;
421*0Sstevel@tonic-gate 			break;
422*0Sstevel@tonic-gate 		}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 		/*
425*0Sstevel@tonic-gate 		 * If this relocation is against a text segment we must make
426*0Sstevel@tonic-gate 		 * sure that the instruction cache is flushed.
427*0Sstevel@tonic-gate 		 */
428*0Sstevel@tonic-gate 		if (textrel) {
429*0Sstevel@tonic-gate 			if (rp->r_type == RELOC_RELATIVE)
430*0Sstevel@tonic-gate 				iflush_range((caddr_t)(ra - 1), 0x8);
431*0Sstevel@tonic-gate 			else
432*0Sstevel@tonic-gate 				iflush_range((caddr_t)ra, 0x4);
433*0Sstevel@tonic-gate 		}
434*0Sstevel@tonic-gate 	}
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	return (relocate_finish(lmp, bound, textrel, ret));
437*0Sstevel@tonic-gate }
438