]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rtld-elf/arm/reloc.c
rtld-elf(1): remove obsolete pre_init() hook
[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 *)((const char *) 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 void
129 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
130 {
131         const Elf_Rel *rel = NULL, *rellim;
132         Elf_Addr relsz = 0;
133         Elf_Addr *where;
134         uint32_t size;
135
136         for (; dynp->d_tag != DT_NULL; dynp++) {
137                 switch (dynp->d_tag) {
138                 case DT_REL:
139                         rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
140                         break;
141                 case DT_RELSZ:
142                         relsz = dynp->d_un.d_val;
143                         break;
144                 }
145         }
146         rellim = (const Elf_Rel *)((const char *)rel + relsz);
147         size = (rellim - 1)->r_offset - rel->r_offset;
148         for (; rel < rellim; rel++) {
149                 where = (Elf_Addr *)(relocbase + rel->r_offset);
150                 
151                 *where += (Elf_Addr)relocbase;
152         }
153 }
154 /*
155  * It is possible for the compiler to emit relocations for unaligned data.
156  * We handle this situation with these inlines.
157  */
158 #define RELOC_ALIGNED_P(x) \
159         (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
160
161 static __inline Elf_Addr
162 load_ptr(void *where)
163 {
164         Elf_Addr res;
165
166         memcpy(&res, where, sizeof(res));
167
168         return (res);
169 }
170
171 static __inline void
172 store_ptr(void *where, Elf_Addr val)
173 {
174
175         memcpy(where, &val, sizeof(val));
176 }
177
178 static int
179 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
180     int flags, RtldLockState *lockstate)
181 {
182         Elf_Addr        *where;
183         const Elf_Sym   *def;
184         const Obj_Entry *defobj;
185         Elf_Addr         tmp;
186         unsigned long    symnum;
187
188         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
189         symnum = ELF_R_SYM(rel->r_info);
190
191         switch (ELF_R_TYPE(rel->r_info)) {
192         case R_ARM_NONE:
193                 break;
194                 
195 #if 1 /* XXX should not occur */
196         case R_ARM_PC24: {      /* word32 S - P + A */
197                 Elf32_Sword addend;
198                 
199                 /*
200                  * Extract addend and sign-extend if needed.
201                  */
202                 addend = *where;
203                 if (addend & 0x00800000)
204                         addend |= 0xff000000;
205                 
206                 def = find_symdef(symnum, obj, &defobj, flags, cache,
207                     lockstate);
208                 if (def == NULL)
209                                 return -1;
210                         tmp = (Elf_Addr)obj->relocbase + def->st_value
211                             - (Elf_Addr)where + (addend << 2);
212                         if ((tmp & 0xfe000000) != 0xfe000000 &&
213                             (tmp & 0xfe000000) != 0) {
214                                 _rtld_error(
215                                 "%s: R_ARM_PC24 relocation @ %p to %s failed "
216                                 "(displacement %ld (%#lx) out of range)",
217                                     obj->path, where,
218                                     obj->strtab + obj->symtab[symnum].st_name,
219                                     (long) tmp, (long) tmp);
220                                 return -1;
221                         }
222                         tmp >>= 2;
223                         *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
224                         dbg("PC24 %s in %s --> %p @ %p in %s",
225                             obj->strtab + obj->symtab[symnum].st_name,
226                             obj->path, (void *)*where, where, defobj->path);
227                         break;
228                 }
229 #endif
230
231                 case R_ARM_ABS32:       /* word32 B + S + A */
232                 case R_ARM_GLOB_DAT:    /* word32 B + S */
233                         def = find_symdef(symnum, obj, &defobj, flags, cache,
234                             lockstate);
235                         if (def == NULL)
236                                 return -1;
237                         if (__predict_true(RELOC_ALIGNED_P(where))) {
238                                 tmp =  *where + (Elf_Addr)defobj->relocbase +
239                                     def->st_value;
240                                 *where = tmp;
241                         } else {
242                                 tmp = load_ptr(where) +
243                                     (Elf_Addr)defobj->relocbase +
244                                     def->st_value;
245                                 store_ptr(where, tmp);
246                         }
247                         dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
248                             obj->strtab + obj->symtab[symnum].st_name,
249                             obj->path, (void *)tmp, where, defobj->path);
250                         break;
251
252                 case R_ARM_RELATIVE:    /* word32 B + A */
253                         if (__predict_true(RELOC_ALIGNED_P(where))) {
254                                 tmp = *where + (Elf_Addr)obj->relocbase;
255                                 *where = tmp;
256                         } else {
257                                 tmp = load_ptr(where) +
258                                     (Elf_Addr)obj->relocbase;
259                                 store_ptr(where, tmp);
260                         }
261                         dbg("RELATIVE in %s --> %p", obj->path,
262                             (void *)tmp);
263                         break;
264
265                 case R_ARM_COPY:
266                         /*
267                          * These are deferred until all other relocations have
268                          * been done.  All we do here is make sure that the
269                          * COPY relocation is not in a shared library.  They
270                          * are allowed only in executable files.
271                          */
272                         if (!obj->mainprog) {
273                                 _rtld_error(
274                         "%s: Unexpected R_COPY relocation in shared library",
275                                     obj->path);
276                                 return -1;
277                         }
278                         dbg("COPY (avoid in main)");
279                         break;
280
281                 case R_ARM_TLS_DTPOFF32:
282                         def = find_symdef(symnum, obj, &defobj, flags, cache,
283                             lockstate);
284                         if (def == NULL)
285                                 return -1;
286
287                         tmp = (Elf_Addr)(def->st_value);
288                         if (__predict_true(RELOC_ALIGNED_P(where)))
289                                 *where = tmp;
290                         else
291                                 store_ptr(where, tmp);
292
293                         dbg("TLS_DTPOFF32 %s in %s --> %p",
294                             obj->strtab + obj->symtab[symnum].st_name,
295                             obj->path, (void *)tmp);
296
297                         break;
298                 case R_ARM_TLS_DTPMOD32:
299                         def = find_symdef(symnum, obj, &defobj, flags, cache,
300                             lockstate);
301                         if (def == NULL)
302                                 return -1;
303
304                         tmp = (Elf_Addr)(defobj->tlsindex);
305                         if (__predict_true(RELOC_ALIGNED_P(where)))
306                                 *where = tmp;
307                         else
308                                 store_ptr(where, tmp);
309
310                         dbg("TLS_DTPMOD32 %s in %s --> %p",
311                             obj->strtab + obj->symtab[symnum].st_name,
312                             obj->path, (void *)tmp);
313
314                         break;
315
316                 case R_ARM_TLS_TPOFF32:
317                         def = find_symdef(symnum, obj, &defobj, flags, cache,
318                             lockstate);
319                         if (def == NULL)
320                                 return -1;
321
322                         if (!defobj->tls_done && !allocate_tls_offset(obj))
323                                 return -1;
324
325                         tmp = (Elf_Addr)def->st_value + defobj->tlsoffset;
326                         if (__predict_true(RELOC_ALIGNED_P(where)))
327                                 *where = tmp;
328                         else
329                                 store_ptr(where, tmp);
330                         dbg("TLS_TPOFF32 %s in %s --> %p",
331                             obj->strtab + obj->symtab[symnum].st_name,
332                             obj->path, (void *)tmp);
333                         break;
334
335
336                 default:
337                         dbg("sym = %lu, type = %lu, offset = %p, "
338                             "contents = %p, symbol = %s",
339                             symnum, (u_long)ELF_R_TYPE(rel->r_info),
340                             (void *)rel->r_offset, (void *)load_ptr(where),
341                             obj->strtab + obj->symtab[symnum].st_name);
342                         _rtld_error("%s: Unsupported relocation type %ld "
343                             "in non-PLT relocations\n",
344                             obj->path, (u_long) ELF_R_TYPE(rel->r_info));
345                         return -1;
346         }
347         return 0;
348 }
349
350 /*
351  *  * Process non-PLT relocations
352  *   */
353 int
354 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
355     RtldLockState *lockstate)
356 {
357         const Elf_Rel *rellim;
358         const Elf_Rel *rel;
359         SymCache *cache;
360         int r = -1;
361         
362         /* The relocation for the dynamic loader has already been done. */
363         if (obj == obj_rtld)
364                 return (0);
365         if ((flags & SYMLOOK_IFUNC) != 0)
366                 /* XXX not implemented */
367                 return (0);
368
369         /*
370          * The dynamic loader may be called from a thread, we have
371          * limited amounts of stack available so we cannot use alloca().
372          */
373         cache = calloc(obj->dynsymcount, sizeof(SymCache));
374         /* No need to check for NULL here */
375
376         rellim = (const Elf_Rel *)((const char *)obj->rel + obj->relsize);
377         for (rel = obj->rel; rel < rellim; rel++) {
378                 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0)
379                         goto done;
380         }
381         r = 0;
382 done:
383         if (cache != NULL)
384                 free(cache);
385         return (r);
386 }
387
388 /*
389  *  * Process the PLT relocations.
390  *   */
391 int
392 reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
393 {
394         const Elf_Rel *rellim;
395         const Elf_Rel *rel;
396                 
397         rellim = (const Elf_Rel *)((const char *)obj->pltrel +
398             obj->pltrelsize);
399         for (rel = obj->pltrel;  rel < rellim;  rel++) {
400                 Elf_Addr *where;
401
402                 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
403                 
404                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
405                 *where += (Elf_Addr )obj->relocbase;
406         }
407         
408         return (0);
409 }
410
411 /*
412  *  * LD_BIND_NOW was set - force relocation for all jump slots
413  *   */
414 int
415 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
416 {
417         const Obj_Entry *defobj;
418         const Elf_Rel *rellim;
419         const Elf_Rel *rel;
420         const Elf_Sym *def;
421         Elf_Addr *where;
422         Elf_Addr target;
423         
424         rellim = (const Elf_Rel *)((const char *)obj->pltrel + obj->pltrelsize);
425         for (rel = obj->pltrel; rel < rellim; rel++) {
426                 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
427                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
428                 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
429                     SYMLOOK_IN_PLT | flags, NULL, lockstate);
430                 if (def == NULL) {
431                         dbg("reloc_jmpslots: sym not found");
432                         return (-1);
433                 }
434                 
435                 target = (Elf_Addr)(defobj->relocbase + def->st_value);         
436                 reloc_jmpslot(where, target, defobj, obj,
437                     (const Elf_Rel *) rel);
438         }
439         
440         obj->jmpslots_done = true;
441         
442         return (0);
443 }
444
445 int
446 reloc_iresolve(Obj_Entry *obj __unused,
447     struct Struct_RtldLockState *lockstate __unused)
448 {
449
450         /* XXX not implemented */
451         return (0);
452 }
453
454 int
455 reloc_iresolve_nonplt(Obj_Entry *obj __unused,
456     struct Struct_RtldLockState *lockstate __unused)
457 {
458
459         /* XXX not implemented */
460         return (0);
461 }
462
463 int
464 reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
465     struct Struct_RtldLockState *lockstate __unused)
466 {
467
468         /* XXX not implemented */
469         return (0);
470 }
471
472 Elf_Addr
473 reloc_jmpslot(Elf_Addr *where, Elf_Addr target,
474     const Obj_Entry *defobj __unused, const Obj_Entry *obj __unused,
475     const Elf_Rel *rel)
476 {
477
478         assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
479
480         if (*where != target && !ld_bind_not)
481                 *where = target;
482         return (target);
483 }
484
485 void
486 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
487 {
488
489 }
490
491 void
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 *
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 }