1 /* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
2
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5 #include <sys/param.h>
6 #include <sys/mman.h>
7
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include "machine/sysarch.h"
15
16 #include "debug.h"
17 #include "rtld.h"
18 #include "paths.h"
19
20 void
arm_abi_variant_hook(Elf_Auxinfo ** aux_info)21 arm_abi_variant_hook(Elf_Auxinfo **aux_info)
22 {
23 Elf_Word ehdr;
24
25 /*
26 * If we're running an old kernel that doesn't provide any data fail
27 * safe by doing nothing.
28 */
29 if (aux_info[AT_EHDRFLAGS] == NULL)
30 return;
31 ehdr = aux_info[AT_EHDRFLAGS]->a_un.a_val;
32
33 /*
34 * Hard float ABI binaries are the default, and use the default paths
35 * and such.
36 */
37 if ((ehdr & EF_ARM_VFP_FLOAT) != 0)
38 return;
39
40 /*
41 * This is a soft float ABI binary. We need to use the soft float
42 * settings. For the moment, the standard library path includes the hard
43 * float paths as well. When upgrading, we need to execute the wrong
44 * kind of binary until we've installed the new binaries. We could go
45 * off whether or not /libsoft exists, but the simplicity of having it
46 * in the path wins.
47 */
48 ld_elf_hints_default = _PATH_SOFT_ELF_HINTS;
49 ld_path_libmap_conf = _PATH_SOFT_LIBMAP_CONF;
50 ld_path_rtld = _PATH_SOFT_RTLD;
51 ld_standard_library_path = SOFT_STANDARD_LIBRARY_PATH;
52 ld_env_prefix = LD_SOFT_;
53 }
54
55 void
init_pltgot(Obj_Entry * obj)56 init_pltgot(Obj_Entry *obj)
57 {
58 if (obj->pltgot != NULL) {
59 obj->pltgot[1] = (Elf_Addr) obj;
60 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
61 }
62 }
63
64 int
do_copy_relocations(Obj_Entry * dstobj)65 do_copy_relocations(Obj_Entry *dstobj)
66 {
67 const Elf_Rel *rellim;
68 const Elf_Rel *rel;
69
70 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */
71
72 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
73 for (rel = dstobj->rel; rel < rellim; rel++) {
74 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
75 void *dstaddr;
76 const Elf_Sym *dstsym;
77 const char *name;
78 size_t size;
79 const void *srcaddr;
80 const Elf_Sym *srcsym;
81 const Obj_Entry *srcobj, *defobj;
82 SymLook req;
83 int res;
84
85 dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
86 dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
87 name = dstobj->strtab + dstsym->st_name;
88 size = dstsym->st_size;
89
90 symlook_init(&req, name);
91 req.ventry = fetch_ventry(dstobj,
92 ELF_R_SYM(rel->r_info));
93 req.flags = SYMLOOK_EARLY;
94
95 for (srcobj = dstobj->next; srcobj != NULL;
96 srcobj = srcobj->next) {
97 res = symlook_obj(&req, srcobj);
98 if (res == 0) {
99 srcsym = req.sym_out;
100 defobj = req.defobj_out;
101 break;
102 }
103 }
104 if (srcobj == NULL) {
105 _rtld_error(
106 "Undefined symbol \"%s\" referenced from COPY relocation in %s",
107 name, dstobj->path);
108 return (-1);
109 }
110
111 srcaddr = (const void *)(defobj->relocbase +
112 srcsym->st_value);
113 memcpy(dstaddr, srcaddr, size);
114 }
115 }
116 return 0;
117 }
118
119 void _rtld_bind_start(void);
120 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
121
122 int open();
123 int _open();
124 void
_rtld_relocate_nonplt_self(Elf_Dyn * dynp,Elf_Addr relocbase)125 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
126 {
127 const Elf_Rel *rel = 0, *rellim;
128 Elf_Addr relsz = 0;
129 Elf_Addr *where;
130 uint32_t size;
131
132 for (; dynp->d_tag != DT_NULL; dynp++) {
133 switch (dynp->d_tag) {
134 case DT_REL:
135 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
136 break;
137 case DT_RELSZ:
138 relsz = dynp->d_un.d_val;
139 break;
140 }
141 }
142 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
143 size = (rellim - 1)->r_offset - rel->r_offset;
144 for (; rel < rellim; rel++) {
145 where = (Elf_Addr *)(relocbase + rel->r_offset);
146
147 *where += (Elf_Addr)relocbase;
148 }
149 }
150 /*
151 * It is possible for the compiler to emit relocations for unaligned data.
152 * We handle this situation with these inlines.
153 */
154 #define RELOC_ALIGNED_P(x) \
155 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
156
157 static __inline Elf_Addr
load_ptr(void * where)158 load_ptr(void *where)
159 {
160 Elf_Addr res;
161
162 memcpy(&res, where, sizeof(res));
163
164 return (res);
165 }
166
167 static __inline void
store_ptr(void * where,Elf_Addr val)168 store_ptr(void *where, Elf_Addr val)
169 {
170
171 memcpy(where, &val, sizeof(val));
172 }
173
174 static int
reloc_nonplt_object(Obj_Entry * obj,const Elf_Rel * rel,SymCache * cache,int flags,RtldLockState * lockstate)175 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
176 int flags, RtldLockState *lockstate)
177 {
178 Elf_Addr *where;
179 const Elf_Sym *def;
180 const Obj_Entry *defobj;
181 Elf_Addr tmp;
182 unsigned long symnum;
183
184 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
185 symnum = ELF_R_SYM(rel->r_info);
186
187 switch (ELF_R_TYPE(rel->r_info)) {
188 case R_ARM_NONE:
189 break;
190
191 #if 1 /* XXX should not occur */
192 case R_ARM_PC24: { /* word32 S - P + A */
193 Elf32_Sword addend;
194
195 /*
196 * Extract addend and sign-extend if needed.
197 */
198 addend = *where;
199 if (addend & 0x00800000)
200 addend |= 0xff000000;
201
202 def = find_symdef(symnum, obj, &defobj, flags, cache,
203 lockstate);
204 if (def == NULL)
205 return -1;
206 tmp = (Elf_Addr)obj->relocbase + def->st_value
207 - (Elf_Addr)where + (addend << 2);
208 if ((tmp & 0xfe000000) != 0xfe000000 &&
209 (tmp & 0xfe000000) != 0) {
210 _rtld_error(
211 "%s: R_ARM_PC24 relocation @ %p to %s failed "
212 "(displacement %ld (%#lx) out of range)",
213 obj->path, where,
214 obj->strtab + obj->symtab[symnum].st_name,
215 (long) tmp, (long) tmp);
216 return -1;
217 }
218 tmp >>= 2;
219 *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
220 dbg("PC24 %s in %s --> %p @ %p in %s",
221 obj->strtab + obj->symtab[symnum].st_name,
222 obj->path, (void *)*where, where, defobj->path);
223 break;
224 }
225 #endif
226
227 case R_ARM_ABS32: /* word32 B + S + A */
228 case R_ARM_GLOB_DAT: /* word32 B + S */
229 def = find_symdef(symnum, obj, &defobj, flags, cache,
230 lockstate);
231 if (def == NULL)
232 return -1;
233 if (__predict_true(RELOC_ALIGNED_P(where))) {
234 tmp = *where + (Elf_Addr)defobj->relocbase +
235 def->st_value;
236 *where = tmp;
237 } else {
238 tmp = load_ptr(where) +
239 (Elf_Addr)defobj->relocbase +
240 def->st_value;
241 store_ptr(where, tmp);
242 }
243 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
244 obj->strtab + obj->symtab[symnum].st_name,
245 obj->path, (void *)tmp, where, defobj->path);
246 break;
247
248 case R_ARM_RELATIVE: /* word32 B + A */
249 if (__predict_true(RELOC_ALIGNED_P(where))) {
250 tmp = *where + (Elf_Addr)obj->relocbase;
251 *where = tmp;
252 } else {
253 tmp = load_ptr(where) +
254 (Elf_Addr)obj->relocbase;
255 store_ptr(where, tmp);
256 }
257 dbg("RELATIVE in %s --> %p", obj->path,
258 (void *)tmp);
259 break;
260
261 case R_ARM_COPY:
262 /*
263 * These are deferred until all other relocations have
264 * been done. All we do here is make sure that the
265 * COPY relocation is not in a shared library. They
266 * are allowed only in executable files.
267 */
268 if (!obj->mainprog) {
269 _rtld_error(
270 "%s: Unexpected R_COPY relocation in shared library",
271 obj->path);
272 return -1;
273 }
274 dbg("COPY (avoid in main)");
275 break;
276
277 case R_ARM_TLS_DTPOFF32:
278 def = find_symdef(symnum, obj, &defobj, flags, cache,
279 lockstate);
280 if (def == NULL)
281 return -1;
282
283 tmp = (Elf_Addr)(def->st_value);
284 if (__predict_true(RELOC_ALIGNED_P(where)))
285 *where = tmp;
286 else
287 store_ptr(where, tmp);
288
289 dbg("TLS_DTPOFF32 %s in %s --> %p",
290 obj->strtab + obj->symtab[symnum].st_name,
291 obj->path, (void *)tmp);
292
293 break;
294 case R_ARM_TLS_DTPMOD32:
295 def = find_symdef(symnum, obj, &defobj, flags, cache,
296 lockstate);
297 if (def == NULL)
298 return -1;
299
300 tmp = (Elf_Addr)(defobj->tlsindex);
301 if (__predict_true(RELOC_ALIGNED_P(where)))
302 *where = tmp;
303 else
304 store_ptr(where, tmp);
305
306 dbg("TLS_DTPMOD32 %s in %s --> %p",
307 obj->strtab + obj->symtab[symnum].st_name,
308 obj->path, (void *)tmp);
309
310 break;
311
312 case R_ARM_TLS_TPOFF32:
313 def = find_symdef(symnum, obj, &defobj, flags, cache,
314 lockstate);
315 if (def == NULL)
316 return -1;
317
318 if (!defobj->tls_done && allocate_tls_offset(obj))
319 return -1;
320
321 /* XXX: FIXME */
322 tmp = (Elf_Addr)def->st_value + defobj->tlsoffset +
323 TLS_TCB_SIZE;
324 if (__predict_true(RELOC_ALIGNED_P(where)))
325 *where = tmp;
326 else
327 store_ptr(where, tmp);
328 dbg("TLS_TPOFF32 %s in %s --> %p",
329 obj->strtab + obj->symtab[symnum].st_name,
330 obj->path, (void *)tmp);
331 break;
332
333
334 default:
335 dbg("sym = %lu, type = %lu, offset = %p, "
336 "contents = %p, symbol = %s",
337 symnum, (u_long)ELF_R_TYPE(rel->r_info),
338 (void *)rel->r_offset, (void *)load_ptr(where),
339 obj->strtab + obj->symtab[symnum].st_name);
340 _rtld_error("%s: Unsupported relocation type %ld "
341 "in non-PLT relocations\n",
342 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
343 return -1;
344 }
345 return 0;
346 }
347
348 /*
349 * * Process non-PLT relocations
350 * */
351 int
reloc_non_plt(Obj_Entry * obj,Obj_Entry * obj_rtld,int flags,RtldLockState * lockstate)352 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
353 RtldLockState *lockstate)
354 {
355 const Elf_Rel *rellim;
356 const Elf_Rel *rel;
357 SymCache *cache;
358 int r = -1;
359
360 /* The relocation for the dynamic loader has already been done. */
361 if (obj == obj_rtld)
362 return (0);
363 if ((flags & SYMLOOK_IFUNC) != 0)
364 /* XXX not implemented */
365 return (0);
366
367 /*
368 * The dynamic loader may be called from a thread, we have
369 * limited amounts of stack available so we cannot use alloca().
370 */
371 cache = calloc(obj->dynsymcount, sizeof(SymCache));
372 /* No need to check for NULL here */
373
374 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
375 for (rel = obj->rel; rel < rellim; rel++) {
376 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0)
377 goto done;
378 }
379 r = 0;
380 done:
381 if (cache != NULL)
382 free(cache);
383 return (r);
384 }
385
386 /*
387 * * Process the PLT relocations.
388 * */
389 int
reloc_plt(Obj_Entry * obj)390 reloc_plt(Obj_Entry *obj)
391 {
392 const Elf_Rel *rellim;
393 const Elf_Rel *rel;
394
395 rellim = (const Elf_Rel *)((char *)obj->pltrel +
396 obj->pltrelsize);
397 for (rel = obj->pltrel; rel < rellim; rel++) {
398 Elf_Addr *where;
399
400 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
401
402 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
403 *where += (Elf_Addr )obj->relocbase;
404 }
405
406 return (0);
407 }
408
409 /*
410 * * LD_BIND_NOW was set - force relocation for all jump slots
411 * */
412 int
reloc_jmpslots(Obj_Entry * obj,int flags,RtldLockState * lockstate)413 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
414 {
415 const Obj_Entry *defobj;
416 const Elf_Rel *rellim;
417 const Elf_Rel *rel;
418 const Elf_Sym *def;
419 Elf_Addr *where;
420 Elf_Addr target;
421
422 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
423 for (rel = obj->pltrel; rel < rellim; rel++) {
424 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
425 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
426 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
427 SYMLOOK_IN_PLT | flags, NULL, lockstate);
428 if (def == NULL) {
429 dbg("reloc_jmpslots: sym not found");
430 return (-1);
431 }
432
433 target = (Elf_Addr)(defobj->relocbase + def->st_value);
434 reloc_jmpslot(where, target, defobj, obj,
435 (const Elf_Rel *) rel);
436 }
437
438 obj->jmpslots_done = true;
439
440 return (0);
441 }
442
443 int
reloc_iresolve(Obj_Entry * obj,struct Struct_RtldLockState * lockstate)444 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
445 {
446
447 /* XXX not implemented */
448 return (0);
449 }
450
451 int
reloc_gnu_ifunc(Obj_Entry * obj,int flags,struct Struct_RtldLockState * lockstate)452 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
453 struct Struct_RtldLockState *lockstate)
454 {
455
456 /* XXX not implemented */
457 return (0);
458 }
459
460 Elf_Addr
reloc_jmpslot(Elf_Addr * where,Elf_Addr target,const Obj_Entry * defobj,const Obj_Entry * obj,const Elf_Rel * rel)461 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
462 const Obj_Entry *obj, const Elf_Rel *rel)
463 {
464
465 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
466
467 if (*where != target)
468 *where = target;
469
470 return target;
471 }
472
473 void
allocate_initial_tls(Obj_Entry * objs)474 allocate_initial_tls(Obj_Entry *objs)
475 {
476 #ifdef ARM_TP_ADDRESS
477 void **_tp = (void **)ARM_TP_ADDRESS;
478 #endif
479
480 /*
481 * Fix the size of the static TLS block by using the maximum
482 * offset allocated so far and adding a bit for dynamic modules to
483 * use.
484 */
485
486 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
487
488 #ifdef ARM_TP_ADDRESS
489 (*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8);
490 #else
491 sysarch(ARM_SET_TP, allocate_tls(objs, NULL, TLS_TCB_SIZE, 8));
492 #endif
493 }
494
495 void *
__tls_get_addr(tls_index * ti)496 __tls_get_addr(tls_index* ti)
497 {
498 char *p;
499 #ifdef ARM_TP_ADDRESS
500 void **_tp = (void **)ARM_TP_ADDRESS;
501
502 p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset);
503 #else
504 void *_tp;
505 __asm __volatile("mrc p15, 0, %0, c13, c0, 3" \
506 : "=r" (_tp));
507 p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset);
508 #endif
509
510 return (p);
511 }
512