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