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 #include <libelf.h>
28 #include <dlfcn.h>
29 #include "machdep.h"
30 #include "reloc.h"
31 #include "msg.h"
32 #include "_librtld.h"
33 #include "alist.h"
34
35 static const char *unknown = 0; /* Stash MSG_INTL(MSG_STR_UNKNOWN) */
36
37 /*
38 * Process all relocation records. A new `Reloc' structure is allocated to
39 * cache the processing decisions deduced, and these will be applied during
40 * update_reloc().
41 * A count of the number of null relocations (i.e., relocations that will be
42 * fixed and whoes records will be nulled out), data and function relocations
43 * is maintained. This allows the relocation records themselves to be
44 * rearranged (localized) later if necessary. Note that the number of function
45 * relocations, although coounted, shouldn't differ from the original file,
46 * the index of a .plt must be maintained to the index of its relocation record
47 * within the associated relocation section.
48 *
49 * The intention behind this file is to maintain as much relocation logic as
50 * possible in a generic form.
51 */
52 int
count_reloc(Cache * cache,Cache * _cache,Rt_map * lmp,int flags,Addr addr,Xword * null,Xword * data,Xword * func,Alist * nodirect)53 count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
54 Xword *null, Xword *data, Xword *func, Alist *nodirect)
55 {
56 Rel *rel;
57 Reloc *reloc;
58 Shdr *shdr;
59 Xword ent, cnt, _cnt;
60 Sym *syms;
61 const char *strs;
62 Cache *__cache;
63 Xword pltndx = 0;
64
65 /*
66 * Determine the number of relocation entries we'll be dealing with.
67 */
68 shdr = _cache->c_shdr;
69 rel = (Rel *)_cache->c_data->d_buf;
70 ent = shdr->sh_entsize;
71 cnt = shdr->sh_size / ent;
72
73 /*
74 * Allocate a relocation structure for this relocation section.
75 */
76 if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
77 return (1);
78 _cache->c_info = (void *)reloc;
79
80 /*
81 * Determine the relocations associated symbol and string table.
82 */
83 __cache = &cache[shdr->sh_link];
84 syms = (Sym *)__cache->c_data->d_buf;
85 shdr = __cache->c_shdr;
86 __cache = &cache[shdr->sh_link];
87 strs = (const char *)__cache->c_data->d_buf;
88
89 /*
90 * Loop through the relocation table.
91 */
92 for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
93 rel = (Rel *)((uintptr_t)rel + ent)) {
94 const char *name;
95 /* LINTED */
96 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
97 uchar_t bind;
98 ulong_t offset = rel->r_offset + addr;
99 Rt_map *_lmp;
100 int _bound, _weak;
101 ulong_t rsymndx = ELF_R_SYM(rel->r_info);
102 Slookup sl;
103 Sresult sr;
104 uint_t binfo;
105 Sym *_sym, *sym = (syms + rsymndx);
106
107 if (type == M_R_JMP_SLOT)
108 reloc->r_pltndx = ++pltndx;
109
110 /*
111 * Analyze the case where no relocations are to be applied.
112 */
113 if ((flags & RTLD_REL_ALL) == 0) {
114 /*
115 * Don't apply any relocations to the new image but
116 * insure their offsets are incremented to reflect any
117 * new fixed address.
118 */
119 reloc->r_flags = FLG_R_INC;
120
121 /*
122 * Undo any relocations that might have already been
123 * applied to the memory image.
124 */
125 if (flags & RTLD_MEMORY) {
126 reloc->r_flags |= FLG_R_UNDO;
127
128 /*
129 * If a copy relocation is involved we'll need
130 * to know the size of the copy.
131 */
132 if (type == M_R_COPY)
133 reloc->r_size = sym->st_size;
134 else
135 reloc->r_size = 0;
136 }
137
138 /*
139 * Save the objects new address.
140 */
141 reloc->r_value = addr;
142
143 if (type == M_R_JMP_SLOT)
144 (*func)++;
145 else
146 (*data)++;
147 continue;
148 }
149
150 /*
151 * Determine the symbol binding of the relocation. Don't assume
152 * that relative relocations are simply M_R_RELATIVE. Although
153 * a pic generated shared object can normally be viewed as
154 * having relative and non-relative relocations, a non-pic
155 * shared object will contain a number of relocations against
156 * local symbols (normally sections). If a relocation is
157 * against a local symbol it qualifies as a relative relocation.
158 */
159 if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
160 (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
161 bind = STB_LOCAL;
162 else
163 bind = STB_GLOBAL;
164
165 /*
166 * Analyze the case where only relative relocations are to be
167 * applied.
168 */
169 if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
170 if (flags & RTLD_MEMORY) {
171 if (bind == STB_LOCAL) {
172 /*
173 * Save the relative relocations from
174 * the memory image. The data itself
175 * might already have been relocated,
176 * thus clear the relocation record so
177 * that it will not be performed again.
178 */
179 reloc->r_flags = FLG_R_CLR;
180 (*null)++;
181 } else {
182 /*
183 * Any non-relative relocation must be
184 * undone, and the relocation records
185 * offset updated to any new fixed
186 * address.
187 */
188 reloc->r_flags =
189 (FLG_R_UNDO | FLG_R_INC);
190 reloc->r_value = addr;
191 if (type == M_R_JMP_SLOT)
192 (*func)++;
193 else
194 (*data)++;
195 }
196 } else {
197 if (bind == STB_LOCAL) {
198 /*
199 * Apply relative relocation to the
200 * file image. Clear the relocation
201 * record so that it will not be
202 * performed again.
203 */
204 reloc->r_flags =
205 (FLG_R_APPLY | FLG_R_CLR);
206 reloc->r_value = addr;
207 if (IS_PC_RELATIVE(type))
208 reloc->r_value -= offset;
209
210 if (unknown == 0)
211 unknown =
212 MSG_INTL(MSG_STR_UNKNOWN);
213 reloc->r_name = unknown;
214 (*null)++;
215 } else {
216 /*
217 * Any non-relative relocation should be
218 * left alone, but its offset should be
219 * updated to any new fixed address.
220 */
221 reloc->r_flags = FLG_R_INC;
222 reloc->r_value = addr;
223 if (type == M_R_JMP_SLOT)
224 (*func)++;
225 else
226 (*data)++;
227 }
228 }
229 continue;
230 }
231
232 /*
233 * Analyze the case where more than just relative relocations
234 * are to be applied.
235 */
236 if (bind == STB_LOCAL) {
237 if (flags & RTLD_MEMORY) {
238 /*
239 * Save the relative relocations from the memory
240 * image. The data itself has already been
241 * relocated, thus clear the relocation record
242 * so that it will not be performed again.
243 */
244 reloc->r_flags = FLG_R_CLR;
245 } else {
246 /*
247 * Apply relative relocation to the file image.
248 * Clear the relocation record so that it will
249 * not be performed again.
250 */
251 reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
252 reloc->r_value = addr;
253 if (IS_PC_RELATIVE(type))
254 reloc->r_value -= offset;
255
256 if (unknown == 0)
257 unknown = MSG_INTL(MSG_STR_UNKNOWN);
258 reloc->r_name = unknown;
259 }
260 (*null)++;
261 continue;
262 }
263
264 /*
265 * At this point we're dealing with a non-relative relocation
266 * that requires the symbol definition.
267 */
268 name = strs + sym->st_name;
269
270 /*
271 * Find the symbol. As the object being investigated is already
272 * a part of this process, the symbol lookup will likely
273 * succeed. However, because of lazy binding, there is still
274 * the possibility of a dangling .plt relocation. dldump()
275 * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
276 * does this for them).
277 *
278 * Initialize the symbol lookup, and symbol result, data
279 * structures.
280 */
281 SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
282 0, rsymndx, sym, type, LKUP_STDRELOC);
283 SRESULT_INIT(sr, name);
284
285 _bound = _weak = 0;
286 _sym = sym;
287 if (lookup_sym(&sl, &sr, &binfo, NULL)) {
288 _lmp = sr.sr_dmap;
289 sym = sr.sr_sym;
290
291 /*
292 * Determine from the various relocation requirements
293 * whether this binding is appropriate. If we're called
294 * from crle(1), RTLD_CONFSET is set, then only inspect
295 * objects selected from the configuration file
296 * (FL1_RT_CONFSET was set during load()).
297 */
298 if (!(flags & RTLD_CONFSET) ||
299 (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
300 if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
301 ((flags & RTLD_REL_EXEC) &&
302 (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
303 ((flags & RTLD_REL_DEPENDS) &&
304 (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
305 ((flags & RTLD_REL_PRELOAD) &&
306 (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
307 ((flags & RTLD_REL_SELF) &&
308 (lmp == _lmp))) {
309 Aliste idx;
310 Word *ndx;
311
312 _bound = 1;
313
314 /*
315 * If this symbol is explicitly defined
316 * as nodirect, don't allow any local
317 * binding.
318 */
319 for (ALIST_TRAVERSE(nodirect, idx,
320 ndx)) {
321 if (*ndx == rsymndx) {
322 _bound = 0;
323 break;
324 }
325 }
326 }
327 }
328 } else {
329 /*
330 * If this is a weak reference and we've been asked to
331 * bind unresolved weak references consider ourself
332 * bound. This category is typically set by clre(1) for
333 * an application cache.
334 */
335 if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
336 (_sym->st_shndx == SHN_UNDEF) &&
337 (flags & RTLD_REL_WEAK))
338 _bound = _weak = 1;
339 }
340
341 if (flags & RTLD_MEMORY) {
342 if (_bound) {
343 /*
344 * We know that all data relocations will have
345 * been performed at process startup thus clear
346 * the relocation record so that it will not be
347 * performed again. However, we don't know what
348 * function relocations have been performed
349 * because of lazy binding - regardless, we can
350 * leave all the function relocation records in
351 * place, because if the function has already
352 * been bound the record won't be referenced
353 * anyway. In the case of using LD_BIND_NOW,
354 * a function may be bound twice - so what.
355 */
356 if (type == M_R_JMP_SLOT) {
357 reloc->r_flags = FLG_R_INC;
358 (*func)++;
359 } else {
360 if (type != M_R_COPY)
361 reloc->r_flags = FLG_R_CLR;
362 (*null)++;
363 }
364 } else {
365 /*
366 * Clear any unrequired relocation.
367 */
368 reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
369 reloc->r_value = addr;
370 if (type == M_R_JMP_SLOT)
371 (*func)++;
372 else
373 (*data)++;
374 }
375 } else {
376 if (_bound) {
377 /*
378 * Apply the global relocation to the file
379 * image. Clear the relocation record so that
380 * it will not be performed again.
381 */
382 if (_weak) {
383 reloc->r_value = 0;
384 reloc->r_size = 0;
385 } else {
386 reloc->r_value = sym->st_value;
387 if (IS_PC_RELATIVE(type))
388 reloc->r_value -= offset;
389 if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
390 (sym->st_shndx != SHN_ABS))
391 reloc->r_value += ADDR(_lmp);
392 reloc->r_size = sym->st_size;
393 }
394
395 reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
396 reloc->r_name = name;
397 if (type == M_R_JMP_SLOT)
398 (*func)++;
399 else
400 (*null)++;
401 } else {
402 /*
403 * Do not apply any unrequired relocations.
404 */
405 reloc->r_flags = FLG_R_INC;
406 reloc->r_value = addr;
407 if (type == M_R_JMP_SLOT)
408 (*func)++;
409 else
410 (*data)++;
411 }
412 }
413 }
414 return (0);
415 }
416
417
418 /*
419 * Perform any relocation updates to the new image using the information from
420 * the `Reloc' structure constructed during count_reloc().
421 */
422 void
update_reloc(Cache * ocache,Cache * icache,Cache * _icache,const char * name,Rt_map * lmp,Rel ** null,Rel ** data,Rel ** func)423 update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
424 Rt_map *lmp, Rel **null, Rel **data, Rel **func)
425 {
426 Shdr *shdr;
427 Rel *rel;
428 Reloc *reloc;
429 Xword ent, cnt, _cnt;
430 Cache *orcache, *ircache = 0;
431 Half ndx;
432
433 /*
434 * Set up to read the output relocation table.
435 */
436 shdr = _icache->c_shdr;
437 rel = (Rel *)_icache->c_data->d_buf;
438 reloc = (Reloc *)_icache->c_info;
439 ent = shdr->sh_entsize;
440 cnt = shdr->sh_size / ent;
441
442 /*
443 * Loop through the relocation table.
444 */
445 for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
446 rel = (Rel *)((uintptr_t)rel + ent)) {
447 uchar_t *iaddr, *oaddr;
448 /* LINTED */
449 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
450 Addr off, bgn, end;
451
452 /*
453 * Ignore null relocations (these may have been created from a
454 * previous dldump() of this image).
455 */
456 if (type == M_R_NONE) {
457 (*null)++;
458 continue;
459 }
460
461 /*
462 * Determine the section being relocated if we haven't already
463 * done so (we may have had to skip over some null relocation to
464 * get to the first valid offset). The System V ABI states that
465 * a relocation sections sh_info field indicates the section
466 * that must be relocated. However, on Intel it seems that the
467 * .rel.plt sh_info records the section index of the .plt, when
468 * in fact it's the .got that gets relocated. In addition we
469 * now create combined relocation sections with -zcomreloc. To
470 * generically be able to cope with these anomalies, search for
471 * the appropriate section to be relocated by comparing the
472 * offset of the first relocation record against each sections
473 * offset and size.
474 */
475 /* BEGIN CSTYLED */
476 #if !defined(__lint)
477 if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
478 (rel->r_offset > end)) {
479 #else
480 /*
481 * lint sees `bgn' and `end' as potentially referenced
482 * before being set.
483 */
484 if (ircache == (Cache *)0) {
485 #endif
486 _icache = icache;
487 _icache++;
488
489 for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
490 _icache++) {
491
492 shdr = _icache->c_shdr;
493 bgn = shdr->sh_addr;
494 end = bgn + shdr->sh_size;
495
496 if ((rel->r_offset >= bgn) &&
497 (rel->r_offset <= end))
498 break;
499 }
500 ircache = &icache[ndx];
501 orcache = &ocache[ndx];
502 }
503 /* END CSTYLED */
504
505 /*
506 * Determine the relocation location of both the input and
507 * output data. Take into account that an input section may be
508 * NOBITS (ppc .plt for example).
509 */
510 off = rel->r_offset - ircache->c_shdr->sh_addr;
511 if (ircache->c_data->d_buf)
512 iaddr = (uchar_t *)ircache->c_data->d_buf + off;
513 else
514 iaddr = 0;
515 oaddr = (uchar_t *)orcache->c_data->d_buf + off;
516
517 /*
518 * Apply the relocation to the new output image. Any base
519 * address, or symbol value, will have been saved in the reloc
520 * structure during count_reloc().
521 */
522 if (reloc->r_flags & FLG_R_APPLY)
523 apply_reloc(rel, reloc, name, oaddr, lmp);
524
525 /*
526 * Undo any relocation that might already been applied to the
527 * memory image by the runtime linker. Using the original
528 * file, determine the relocation offset original value and
529 * restore the new image to that value.
530 */
531 if ((reloc->r_flags & FLG_R_UNDO) &&
532 (FLAGS(lmp) & FLG_RT_RELOCED))
533 undo_reloc(rel, oaddr, iaddr, reloc);
534
535 /*
536 * If a relocation has been applied then the relocation record
537 * should be cleared so that the relocation isn't applied again
538 * when the new image is used.
539 */
540 if (reloc->r_flags & FLG_R_CLR) {
541 if (type == M_R_JMP_SLOT) {
542 clear_reloc(*func);
543 *func = (Rel *)((uintptr_t)*func + ent);
544 } else {
545 clear_reloc(*null);
546 *null = (Rel *)((uintptr_t)*null + ent);
547 }
548 }
549
550 /*
551 * If a relocation isn't applied, update the relocation record
552 * to take into account the new address of the image.
553 */
554 if (reloc->r_flags & FLG_R_INC) {
555 if (type == M_R_JMP_SLOT) {
556 inc_reloc(*func, rel, reloc, oaddr, iaddr);
557 *func = (Rel *)((uintptr_t)*func + ent);
558 } else {
559 inc_reloc(*data, rel, reloc, oaddr, iaddr);
560 *data = (Rel *)((uintptr_t)*data + ent);
561 }
562 }
563 }
564 }
565