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