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