]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rtld-elf/arm/reloc.c
Update llvm, clang and lldb to trunk r257626, and update build glue.
[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/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
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
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             
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
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
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
168 store_ptr(void *where, Elf_Addr val)
169 {
170
171         memcpy(where, &val, sizeof(val));
172 }
173
174 static int
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
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
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
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
444 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
445 {
446
447         /* XXX not implemented */
448         return (0);
449 }
450
451 int
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
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
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 *
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 }