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