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