reloc.c revision 1.9 1 /* $NetBSD: reloc.c,v 1.9 1999/02/22 17:06:11 pk Exp $ */
2
3 /*
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by John Polstra.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Dynamic linker for ELF.
36 *
37 * John Polstra <jdp (at) polstra.com>.
38 */
39
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <sys/types.h>
49 #include <sys/mman.h>
50 #include <dirent.h>
51
52 #include "debug.h"
53 #include "rtld.h"
54
55 #if defined(__alpha__) || defined(__powerpc__) || defined(__i386__)
56 /*
57 * XXX: These don't work for the alpha and i386; don't know about powerpc
58 * The alpha and the i386 avoid the problem by compiling everything PIC.
59 * These relocation are supposed to be writing the address of the
60 * function to be called on the bss.rel or bss.rela segment, but:
61 * - st_size == 0
62 * - on the i386 at least the call instruction is a direct call
63 * not an indirect call.
64 */
65 static int
66 _rtld_do_copy_relocation(
67 const Obj_Entry *dstobj,
68 const Elf_RelA *rela)
69 {
70 void *dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
71 const Elf_Sym *dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
72 const char *name = dstobj->strtab + dstsym->st_name;
73 unsigned long hash = _rtld_elf_hash(name);
74 size_t size = dstsym->st_size;
75 const void *srcaddr;
76 const Elf_Sym *srcsym;
77 Obj_Entry *srcobj;
78
79 for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next)
80 if ((srcsym = _rtld_symlook_obj(name, hash, srcobj, false)) != NULL)
81 break;
82
83 if (srcobj == NULL) {
84 _rtld_error("Undefined symbol \"%s\" referenced from COPY"
85 " relocation in %s", name, dstobj->path);
86 return -1;
87 }
88
89 srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
90 memcpy(dstaddr, srcaddr, size);
91 #ifdef RTLD_DEBUG_RELOC
92 dbg("COPY %s %s %s --> src=%p dst=%p *dst= %p size %d",
93 dstobj->path, srcobj->path, name, (void *)srcaddr, (void *)dstaddr,
94 (void *)*(long *)dstaddr, size);
95 #endif
96 return 0;
97 }
98 #endif /* __alpha__ || __powerpc__ || __i386__ */
99
100 /*
102 * Process the special R_xxx_COPY relocations in the main program. These
103 * copy data from a shared object into a region in the main program's BSS
104 * segment.
105 *
106 * Returns 0 on success, -1 on failure.
107 */
108 int
109 _rtld_do_copy_relocations(
110 const Obj_Entry *dstobj)
111 {
112 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
113
114 #if defined(__alpha__) || defined(__powerpc__) || defined(__i386__)
115 if (dstobj->rel != NULL) {
116 const Elf_Rel *rel;
117 for (rel = dstobj->rel; rel < dstobj->rellim; ++rel) {
118 if (ELF_R_TYPE(rel->r_info) == R_TYPE(COPY)) {
119 Elf_RelA ourrela;
120 ourrela.r_info = rel->r_info;
121 ourrela.r_offset = rel->r_offset;
122 ourrela.r_addend = 0;
123 if (_rtld_do_copy_relocation(dstobj, &ourrela) < 0)
124 return -1;
125 }
126 }
127 }
128
129 if (dstobj->rela != NULL) {
130 const Elf_RelA *rela;
131 for (rela = dstobj->rela; rela < dstobj->relalim; ++rela) {
132 if (ELF_R_TYPE(rela->r_info) == R_TYPE(COPY)) {
133 if (_rtld_do_copy_relocation(dstobj, rela) < 0)
134 return -1;
135 }
136 }
137 }
138 #endif /* __alpha__ || __powerpc__ || __i386__ */
139
140 return 0;
141 }
142
143 #ifdef __sparc__
144 /*
145 * The following table holds for each relocation type:
146 * - the width in bits of the memory location the relocation
147 * applies to (not currently used)
148 * - the number of bits the relocation value must be shifted to the
149 * right (i.e. discard least significant bits) to fit into
150 * the appropriate field in the instruction word.
151 * - flags indicating whether
152 * * the relocation involves a symbol
153 * * the relocation is relative to the current position
154 * * the relocation is for a GOT entry
155 * * the relocation is relative to the load address
156 *
157 */
158 #define _RF_S 0x80000000 /* Resolve symbol */
159 #define _RF_A 0x40000000 /* Use addend */
160 #define _RF_P 0x20000000 /* Location relative */
161 #define _RF_G 0x10000000 /* GOT offset */
162 #define _RF_B 0x08000000 /* Load address relative */
163 #define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
164 #define _RF_RS(s) ( (s) & 0xff) /* right shift */
165 static int reloc_target_flags[] = {
166 0, /* NONE */
167 _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
168 _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
169 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */
170 _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */
171 _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */
172 _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */
173 _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */
174 _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */
175 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */
176 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */
177 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */
178 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */
179 _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */
180 _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */
181 _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */
182 _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */
183 _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */
184 _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */
185 _RF_SZ(32) | _RF_RS(0), /* COPY */
186 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */
187 _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */
188 _RF_A| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */
189 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* UA_32 */
190
191 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* PLT32 */
192 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* HIPLT22 */
193 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */
194 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */
195 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* PCPLT22 */
196 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */
197 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 10 */
198 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 11 */
199 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 64 */
200 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */
201 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* HH22 */
202 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* HM10 */
203 _RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* LM22 */
204 _RF_S|_RF_A|_RF_P|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* WDISP16 */
205 _RF_S|_RF_A|_RF_P|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* WDISP19 */
206 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */
207 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 7 */
208 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 5 */
209 /*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 6 */
210 };
211
212 #define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
213 #define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
214 #define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
215 #define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
216
217 static int reloc_target_bitmask[] = {
218 #define _BM(x) (~(-(1ULL << (x))))
219 0, /* NONE */
220 _BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */
221 _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */
222 _BM(30), _BM(22), /* WDISP30, WDISP22 */
223 _BM(22), _BM(22), /* HI22, _22 */
224 _BM(13), _BM(10), /* RELOC_13, _LO10 */
225 _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */
226 _BM(10), _BM(22), /* _PC10, _PC22 */
227 _BM(30), 0, /* _WPLT30, _COPY */
228 -1, -1, _BM(22), /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
229 _BM(32), _BM(32), /* _UA32, PLT32 */
230 _BM(22), _BM(10), /* _HIPLT22, LOPLT10 */
231 _BM(32), _BM(22), _BM(10), /* _PCPLT32, _PCPLT22, _PCPLT10 */
232 _BM(10), _BM(11), -1, /* _10, _11, _64 */
233 _BM(10), _BM(22), /* _OLO10, _HH22 */
234 _BM(10), _BM(22), /* _HM10, _LM22 */
235 _BM(16), _BM(19), /* _WDISP16, _WDISP19 */
236 -1, /* GLOB_JMP */
237 _BM(7), _BM(5), _BM(6) /* _7, _5, _6 */
238 #undef _BM
239 };
240 #define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
241
242 static int
243 _rtld_relocate_nonplt_object(
244 const Obj_Entry *obj,
245 const Elf_RelA *rela)
246 {
247 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
248 Elf_Word type, value, mask;
249
250 type = ELF_R_TYPE(rela->r_info);
251 if (type == R_TYPE(NONE))
252 return (0);
253
254 /*
255 * We use the fact that relocation types are an `enum'
256 * Note: R_SPARC_6 is currently numerically largest.
257 */
258 if (type > R_TYPE(6))
259 return (-1);
260
261 value = rela->r_addend;
262 if (RELOC_RESOLVE_SYMBOL(type)) {
263 const Elf_Sym *def;
264 const Obj_Entry *defobj;
265
266 /* Find the symbol */
267 def = _rtld_find_symdef(_rtld_objlist, rela->r_info,
268 NULL, obj, &defobj, false);
269 if (def == NULL)
270 return (-1);
271
272 /* Add in the symbol's absolute address */
273 value += (Elf_Word)(defobj->relocbase + def->st_value);
274 }
275
276 if (RELOC_PC_RELATIVE(type)) {
277 value -= (Elf_Word)where;
278 }
279
280 mask = RELOC_VALUE_BITMASK(type);
281 value >>= RELOC_VALUE_RIGHTSHIFT(type);
282 value &= mask;
283
284 /* We ignore alignment restrictions here */
285 *where &= ~mask;
286 *where |= value;
287 return (0);
288 }
289
290 static int
291 __rtld_relocate_plt_object(
292 const Obj_Entry *obj,
293 const Elf_RelA *rela,
294 bool bind_now,
295 caddr_t *addrp)
296 {
297 const Elf_Sym *def;
298 const Obj_Entry *defobj;
299 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
300 Elf_Addr value;
301
302 if (bind_now == 0 && obj->pltgot != NULL)
303 return (0);
304
305 /* Fully resolve procedure addresses now */
306
307 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
308
309 def = _rtld_find_symdef(_rtld_objlist, rela->r_info,
310 NULL, obj, &defobj, true);
311 if (def == NULL)
312 return (-1);
313
314 value = (Elf_Addr) (defobj->relocbase + def->st_value);
315
316 #ifdef RTLD_DEBUG_RELOC
317 dbg("bind now %d/fixup in %s --> old=%p new=%p",
318 (int)bind_now,
319 defobj->strtab + def->st_name,
320 (void *)*where, (void *)value);
321 #endif
322
323 /*
324 * At the PLT entry pointed at by `where', we now construct
325 * a direct transfer to the now fully resolved function
326 * address. The resulting code in the jump slot is:
327 *
328 * sethi %hi(addr), %g1
329 * jmp %g1+%lo(addr)
330 * nop ! delay slot
331 */
332 #define SETHI 0x03000000
333 #define JMP 0x81c06000
334 #define NOP 0x01000000
335 where[0] = SETHI | ((value >> 10) & 0x003fffff);
336 where[1] = JMP | (value & 0x000003ff);
337 where[2] = NOP;
338
339 if (addrp != NULL)
340 *addrp = (caddr_t)value;
341
342 return (0);
343 }
344
345 #define _rtld_relocate_plt_object(obj, rela, bind_now) \
346 __rtld_relocate_plt_object(obj, rela, bind_now, NULL)
347
348 caddr_t
349 _rtld_bind(
350 const Obj_Entry *obj,
351 Elf_Word reloff)
352 {
353 const Elf_RelA *rela;
354 Elf_RelA ourrela;
355 caddr_t addr;
356
357 if (obj->pltrel != NULL) {
358 const Elf_Rel *rel;
359
360 rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff);
361 ourrela.r_info = rel->r_info;
362 ourrela.r_offset = rel->r_offset;
363 rela = &ourrela;
364 } else {
365 rela = (const Elf_RelA *) ((caddr_t) obj->pltrela + reloff);
366 }
367
368 if (__rtld_relocate_plt_object(obj, rela, true, &addr) < 0)
369 _rtld_die();
370
371 return (addr);
372 return *(caddr_t *)(obj->relocbase + rela->r_offset);
373 }
374
375 #else /* __sparc__ */
376
377 static int
378 _rtld_relocate_nonplt_object(
379 const Obj_Entry *obj,
380 const Elf_RelA *rela)
381 {
382 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
383
384 switch (ELF_R_TYPE(rela->r_info)) {
385
386 case R_TYPE(NONE):
387 break;
388
389 #ifdef __i386__
390 case R_TYPE(GOT32): {
391 const Elf_Sym *def;
392 const Obj_Entry *defobj;
393
394 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
395 if (def == NULL)
396 return -1;
397
398 if (*where != (Elf_Addr) (defobj->relocbase + def->st_value))
399 *where = (Elf_Addr) (defobj->relocbase + def->st_value);
400 #ifdef RTLD_DEBUG_RELOC
401 dbg("GOT32 %s in %s --> %p in %s",
402 defobj->strtab + def->st_name, obj->path,
403 (void *)*where, defobj->path);
404 #endif
405 break;
406 }
407
408 case R_TYPE(PC32):
409 /*
410 * I don't think the dynamic linker should ever see this
411 * type of relocation. But the binutils-2.6 tools sometimes
412 * generate it.
413 */
414 {
415 const Elf_Sym *def;
416 const Obj_Entry *defobj;
417
418 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
419 if (def == NULL)
420 return -1;
421
422 *where += (Elf_Addr) (defobj->relocbase + def->st_value)
423 - (Elf_Addr) where;
424 #ifdef RTLD_DEBUG_RELOC
425 dbg("PC32 %s in %s --> %p in %s",
426 defobj->strtab + def->st_name, obj->path,
427 (void *)*where, defobj->path);
428 #endif
429 break;
430 }
431
432 case R_TYPE(32): {
433 const Elf_Sym *def;
434 const Obj_Entry *defobj;
435
436 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
437 if (def == NULL)
438 return -1;
439
440 *where += (Elf_Addr)(defobj->relocbase + def->st_value);
441 #ifdef RTLD_DEBUG_RELOC
442 dbg("32 %s in %s --> %p in %s",
443 defobj->strtab + def->st_name, obj->path,
444 (void *)*where, defobj->path);
445 #endif
446 break;
447 }
448 #endif /* __i386__ */
449
450 #ifdef __alpha__
451 case R_ALPHA_REFQUAD: {
452 const Elf_Sym *def;
453 const Obj_Entry *defobj;
454 Elf_Addr tmp_value;
455
456 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
457 if (def == NULL)
458 return -1;
459
460 tmp_value = (Elf_Addr) (defobj->relocbase + def->st_value)
461 + *where + rela->r_addend;
462 if (*where != tmp_value)
463 *where = tmp_value;
464 #ifdef RTLD_DEBUG_RELOC
465 dbg("REFQUAD %s in %s --> %p in %s",
466 defobj->strtab + def->st_name, obj->path,
467 (void *)*where, defobj->path);
468 #endif
469 break;
470 }
471 #endif /* __alpha__ */
472
473 #if defined(__i386__) || defined(__alpha__)
474 case R_TYPE(GLOB_DAT):
475 {
476 const Elf_Sym *def;
477 const Obj_Entry *defobj;
478
479 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
480 if (def == NULL)
481 return -1;
482
483 if (*where != (Elf_Addr) (defobj->relocbase + def->st_value))
484 *where = (Elf_Addr) (defobj->relocbase + def->st_value);
485 #ifdef RTLD_DEBUG_RELOC
486 dbg("GLOB_DAT %s in %s --> %p in %s",
487 defobj->strtab + def->st_name, obj->path,
488 (void *)*where, defobj->path);
489 #endif
490 break;
491 }
492
493 case R_TYPE(RELATIVE): {
494 extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
495 extern Elf_Dyn _DYNAMIC;
496
497 if (obj != &_rtld_objself ||
498 (caddr_t)where < (caddr_t)_GLOBAL_OFFSET_TABLE_ ||
499 (caddr_t)where >= (caddr_t)&_DYNAMIC) {
500 *where += (Elf_Addr) obj->relocbase;
501 #ifdef RTLD_DEBUG_RELOC
502 dbg("RELATIVE in %s --> %p", obj->path, (void *)*where);
503 #endif
504 }
505 #ifdef RTLD_DEBUG_RELOC
506 else
507 dbg("RELATIVE in %s stays at %p", obj->path, (void *)*where);
508 #endif
509 break;
510 }
511
512 case R_TYPE(COPY): {
513 /*
514 * These are deferred until all other relocations have
515 * been done. All we do here is make sure that the COPY
516 * relocation is not in a shared library. They are allowed
517 * only in executable files.
518 */
519 if (!obj->mainprog) {
520 _rtld_error("%s: Unexpected R_COPY relocation in shared library",
521 obj->path);
522 return -1;
523 }
524 #ifdef RTLD_DEBUG_RELOC
525 dbg("COPY (avoid in main)");
526 #endif
527 break;
528 }
529 #endif /* __i386__ || __alpha__ */
530
531 #ifdef __mips__
532 case R_TYPE(REL32): {
533 /* 32-bit PC-relative reference */
534
535 const Elf_Sym *def;
536 const Obj_Entry *defobj;
537
538 def = obj->symtab + ELF_R_SYM(rela->r_info);
539
540 if (ELF_SYM_BIND(def->st_info) == Elf_estb_local &&
541 (ELF_SYM_TYPE(def->st_info) == Elf_estt_section ||
542 ELF_SYM_TYPE(def->st_info) == Elf_estt_notype)) {
543 *where += (Elf_Addr) obj->relocbase;
544 #ifdef RTLD_DEBUG_RELOC
545 dbg("REL32 in %s --> %p", obj->path, (void *)*where);
546 #endif
547 } else {
548 /* XXX maybe do something re: bootstrapping? */
549 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj,
550 &defobj, false);
551 if (def == NULL)
552 return -1;
553 *where += (Elf_Addr)(defobj->relocbase + def->st_value);
554 #ifdef RTLD_DEBUG_RELOC
555 dbg("REL32 %s in %s --> %p in %s",
556 defobj->strtab + def->st_name, obj->path,
557 (void *)*where, defobj->path);
558 #endif
559 }
560 break;
561 }
562
563 #endif /* mips */
564
565 #ifdef __powerpc__
566 case R_TYPE(32): /* word32 S + A */
567 case R_TYPE(GLOB_DAT): { /* word32 S + A */
568 const Elf_Sym *def;
569 const Obj_Entry *defobj;
570 Elf_Addr x;
571
572 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, false);
573 if (def == NULL)
574 return -1;
575
576 x = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
577
578 if (*where != x)
579 *where = x;
580 #ifdef RTLD_DEBUG_RELOC
581 dbg("32/GLOB_DAT %s in %s --> %p in %s",
582 defobj->strtab + def->st_name, obj->path,
583 (void *)*where, defobj->path);
584 #endif
585 break;
586 }
587
588 case R_TYPE(COPY):
589 #ifdef RTLD_DEBUG_RELOC
590 dbg("COPY");
591 #endif
592 break;
593
594 case R_TYPE(JMP_SLOT):
595 #ifdef RTLD_DEBUG_RELOC
596 dbg("JMP_SLOT");
597 #endif
598 break;
599
600 case R_TYPE(RELATIVE): { /* word32 B + A */
601 if (obj == &_rtld_objself &&
602 *where == (Elf_Addr)obj->relocbase + rela->r_addend)
603 break; /* GOT - already done */
604
605 *where = (Elf_Addr)obj->relocbase + rela->r_addend;
606 #ifdef RTLD_DEBUG_RELOC
607 dbg("RELATIVE in %s --> %p", obj->path, (void *)*where);
608 #endif
609 break;
610 }
611 #endif /* __powerpc__ */
612
613 default: {
614 const Elf_Sym *def;
615 const Obj_Entry *defobj;
616
617 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, true);
618 dbg("sym = %lu, type = %lu, offset = %p, addend = %p, contents = %p, symbol = %s",
619 (u_long)ELF_R_SYM(rela->r_info), (u_long)ELF_R_TYPE(rela->r_info),
620 (void *)rela->r_offset, (void *)rela->r_addend, (void *)*where,
621 def ? defobj->strtab + def->st_name : "??");
622 _rtld_error("%s: Unsupported relocation type %d in non-PLT relocations\n",
623 obj->path, ELF_R_TYPE(rela->r_info));
624 return -1;
625 }
626 }
627 return 0;
628 }
629
630
631
632 static int
633 _rtld_relocate_plt_object(
634 const Obj_Entry *obj,
635 const Elf_RelA *rela,
636 bool bind_now)
637 {
638 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
639 Elf_Addr new_value;
640
641 /* Fully resolve procedure addresses now */
642
643 #if defined(__powerpc__)
644 return _rtld_reloc_powerpc_plt(obj, rela, bind_now);
645 #endif
646
647 #if defined(__alpha__) || defined(__i386__) /* (jrs) */
648 if (bind_now || obj->pltgot == NULL) {
649 const Elf_Sym *def;
650 const Obj_Entry *defobj;
651
652 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
653
654 def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, &defobj, true);
655 if (def == NULL)
656 return -1;
657
658 new_value = (Elf_Addr) (defobj->relocbase + def->st_value);
659 #ifdef RTLD_DEBUG_RELOC
660 dbg("bind now %d/fixup in %s --> old=%p new=%p",
661 (int)bind_now,
662 defobj->strtab + def->st_name,
663 (void *)*where, (void *)new_value);
664 #endif
665 } else
666 #endif /* __alpha__ (jrs) */
667 if (!obj->mainprog) {
668 /* Just relocate the GOT slots pointing into the PLT */
669 new_value = *where + (Elf_Addr) (obj->relocbase);
670 #ifdef RTLD_DEBUG_RELOC
671 dbg("fixup !main in %s --> %p", obj->path, (void *)*where);
672 #endif
673 } else {
674 return 0;
675 }
676 /*
677 * Since this page is probably copy-on-write, let's not write
678 * it unless we really really have to.
679 */
680 if (*where != new_value)
681 *where = new_value;
682 return 0;
683 }
684
685 caddr_t
686 _rtld_bind(
687 const Obj_Entry *obj,
688 Elf_Word reloff)
689 {
690 const Elf_RelA *rela;
691 Elf_RelA ourrela;
692
693 if (obj->pltrel != NULL) {
694 ourrela.r_info = ((const Elf_Rel *) ((caddr_t) obj->pltrel + reloff))->r_info;
695 ourrela.r_offset = ((const Elf_Rel *) ((caddr_t) obj->pltrel + reloff))->r_offset;
696 rela = &ourrela;
697 } else {
698 rela = (const Elf_RelA *) ((caddr_t) obj->pltrela + reloff);
699 }
700
701 if (__rtld_relocate_plt_object(obj, rela, true) < 0)
702 _rtld_die();
703
704 return *(caddr_t *)(obj->relocbase + rela->r_offset);
705 }
706 #endif /* __sparc__ */
707
708 /*
709 * Relocate newly-loaded shared objects. The argument is a pointer to
710 * the Obj_Entry for the first such object. All objects from the first
711 * to the end of the list of objects are relocated. Returns 0 on success,
712 * or -1 on failure.
713 */
714 int
715 _rtld_relocate_objects(
716 Obj_Entry *first,
717 bool bind_now)
718 {
719 Obj_Entry *obj;
720 int ok = 1;
721
722 for (obj = first; obj != NULL; obj = obj->next) {
723
724 if (obj->nbuckets == 0 || obj->nchains == 0
725 || obj->buckets == NULL || obj->symtab == NULL
726 || obj->strtab == NULL) {
727 _rtld_error("%s: Shared object has no run-time symbol table",
728 obj->path);
729 return -1;
730 }
731
732 dbg(" relocating %s (%ld/%ld rel/rela, %ld/%ld plt rel/rela)",
733 obj->path,
734 (long)(obj->rellim - obj->rel), (long)(obj->relalim - obj->rela),
735 (long)(obj->pltrellim - obj->pltrel),
736 (long)(obj->pltrelalim - obj->pltrela));
737
738 if (obj->textrel) {
739 /* There are relocations to the write-protected text segment. */
740 if (mprotect(obj->mapbase, obj->textsize,
741 PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
742 _rtld_error("%s: Cannot write-enable text segment: %s",
743 obj->path, xstrerror(errno));
744 return -1;
745 }
746 }
747
748 if (obj->rel != NULL) {
749 /* Process the non-PLT relocations. */
750 const Elf_Rel *rel;
751 for (rel = obj->rel; rel < obj->rellim; ++rel) {
752 Elf_RelA ourrela;
753 ourrela.r_info = rel->r_info;
754 ourrela.r_offset = rel->r_offset;
755 #if defined(__mips__)
756 /* rel->r_offset is not valid on mips? */
757 if (ELF_R_TYPE(ourrela.r_info) == R_TYPE(NONE))
758 ourrela.r_addend = 0;
759 else
760 #endif
761 ourrela.r_addend = *(Elf_Word *) (obj->relocbase + rel->r_offset);
762
763 if (_rtld_relocate_nonplt_object(obj, &ourrela) < 0)
764 ok = 0;
765 }
766 }
767
768 if (obj->rela != NULL) {
769 /* Process the non-PLT relocations. */
770 const Elf_RelA *rela;
771 for (rela = obj->rela; rela < obj->relalim; ++rela) {
772 if (_rtld_relocate_nonplt_object(obj, rela) < 0)
773 ok = 0;
774 }
775 }
776
777 if (obj->textrel) { /* Re-protected the text segment. */
778 if (mprotect(obj->mapbase, obj->textsize,
779 PROT_READ|PROT_EXEC) == -1) {
780 _rtld_error("%s: Cannot write-protect text segment: %s",
781 obj->path, xstrerror(errno));
782 return -1;
783 }
784 }
785
786 /* Process the PLT relocations. */
787 if (obj->pltrel != NULL) {
788 const Elf_Rel *rel;
789 for (rel = obj->pltrel; rel < obj->pltrellim; ++rel) {
790 Elf_RelA ourrela;
791 ourrela.r_info = rel->r_info;
792 ourrela.r_offset = rel->r_offset;
793 ourrela.r_addend = *(Elf_Word *) (obj->relocbase + rel->r_offset);
794 if (_rtld_relocate_plt_object(obj, &ourrela, bind_now) < 0)
795 ok = 0;
796 }
797 }
798
799 if (obj->pltrela != NULL) {
800 const Elf_RelA *rela;
801 for (rela = obj->pltrela; rela < obj->pltrelalim; ++rela) {
802 if (_rtld_relocate_plt_object(obj, rela, bind_now) < 0)
803 ok = 0;
804 }
805 }
806
807 if (!ok)
808 return -1;
809
810
811 /* Set some sanity-checking numbers in the Obj_Entry. */
812 obj->magic = RTLD_MAGIC;
813 obj->version = RTLD_VERSION;
814
815 /* Fill in the dynamic linker entry points. */
816 obj->dlopen = _rtld_dlopen;
817 obj->dlsym = _rtld_dlsym;
818 obj->dlerror = _rtld_dlerror;
819 obj->dlclose = _rtld_dlclose;
820
821 /* Set the special PLTGOT entries. */
822 if (obj->pltgot != NULL) {
823 #if defined(__i386__)
824 obj->pltgot[1] = (Elf_Addr) obj;
825 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
826 #endif
827 #if defined(__alpha__)
828 /* This function will be called to perform the relocation. */
829 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
830 /* Identify this shared object */
831 obj->pltgot[3] = (Elf_Addr) obj;
832 #endif
833 #if defined(__mips__)
834 _rtld_relocate_mips_got(obj);
835
836 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
837 /* XXX only if obj->pltgot[1] & 0x80000000 ?? */
838 obj->pltgot[1] |= (Elf_Addr) obj;
839 #endif
840 #if defined(__powerpc__)
841 _rtld_setup_powerpc_plt(obj);
842 #endif
843 #if defined(__sparc__)
844 /*
845 * PLTGOT is the PLT on the sparc.
846 * The first entry holds the call the dynamic linker.
847 * We construct a `call' instruction that transfers
848 * to `_rtld_bind_start()'.
849 * The second entry holds the object identification.
850 * Note: each PLT entry is three words long.
851 */
852 obj->pltgot[1] = 0x40000000 |
853 ((Elf_Addr)&_rtld_bind_start - (Elf_Addr)&obj->pltgot[1]);
854 obj->pltgot[3] = (Elf_Addr) obj;
855 #endif
856 }
857 }
858
859 return 0;
860 }
861