]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - libexec/rtld-elf/arm/reloc.c
MFC r233231:
[FreeBSD/stable/9.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 #include "debug.h"
14 #include "rtld.h"
15
16 void
17 init_pltgot(Obj_Entry *obj)
18 {       
19         if (obj->pltgot != NULL) {
20                 obj->pltgot[1] = (Elf_Addr) obj;
21                 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
22         }
23 }
24
25 int             
26 do_copy_relocations(Obj_Entry *dstobj)
27 {
28         const Elf_Rel *rellim;
29         const Elf_Rel *rel;
30
31         assert(dstobj->mainprog);       /* COPY relocations are invalid elsewhere */
32
33         rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
34         for (rel = dstobj->rel;  rel < rellim;  rel++) {
35                 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
36                         void *dstaddr;
37                         const Elf_Sym *dstsym;
38                         const char *name;
39                         size_t size;
40                         const void *srcaddr;
41                         const Elf_Sym *srcsym;
42                         const Obj_Entry *srcobj, *defobj;
43                         SymLook req;
44                         int res;
45                         
46                         dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
47                         dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
48                         name = dstobj->strtab + dstsym->st_name;
49                         size = dstsym->st_size;
50
51                         symlook_init(&req, name);
52                         req.ventry = fetch_ventry(dstobj,
53                             ELF_R_SYM(rel->r_info));
54                         req.flags = SYMLOOK_EARLY;
55
56                         for (srcobj = dstobj->next;  srcobj != NULL; 
57                              srcobj = srcobj->next) {
58                                 res = symlook_obj(&req, srcobj);
59                                 if (res == 0) {
60                                         srcsym = req.sym_out;
61                                         defobj = req.defobj_out;
62                                         break;
63                                 }
64                         }                       
65                         if (srcobj == NULL) {
66                                 _rtld_error(
67 "Undefined symbol \"%s\" referenced from COPY relocation in %s",
68                                     name, dstobj->path);
69                                 return (-1);
70                         }
71                         
72                         srcaddr = (const void *)(defobj->relocbase +
73                             srcsym->st_value);
74                         memcpy(dstaddr, srcaddr, size);
75                 }
76         }
77         return 0;                            
78 }
79
80 void _rtld_bind_start(void);
81 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
82
83 int open();
84 int _open();
85 void
86 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
87 {
88         const Elf_Rel *rel = 0, *rellim;
89         Elf_Addr relsz = 0;
90         Elf_Addr *where;
91         uint32_t size;
92
93         for (; dynp->d_tag != DT_NULL; dynp++) {
94                 switch (dynp->d_tag) {
95                 case DT_REL:
96                         rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
97                         break;
98                 case DT_RELSZ:
99                         relsz = dynp->d_un.d_val;
100                         break;
101                 }
102         }
103         rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
104         size = (rellim - 1)->r_offset - rel->r_offset;
105         for (; rel < rellim; rel++) {
106                 where = (Elf_Addr *)(relocbase + rel->r_offset);
107                 
108                 *where += (Elf_Addr)relocbase;
109         }
110 }
111 /*
112  * It is possible for the compiler to emit relocations for unaligned data.
113  * We handle this situation with these inlines.
114  */
115 #define RELOC_ALIGNED_P(x) \
116         (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
117
118 static __inline Elf_Addr
119 load_ptr(void *where)
120 {
121         Elf_Addr res;
122
123         memcpy(&res, where, sizeof(res));
124
125         return (res);
126 }
127
128 static __inline void
129 store_ptr(void *where, Elf_Addr val)
130 {
131
132         memcpy(where, &val, sizeof(val));
133 }
134
135 static int
136 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
137     int flags, RtldLockState *lockstate)
138 {
139         Elf_Addr        *where;
140         const Elf_Sym   *def;
141         const Obj_Entry *defobj;
142         Elf_Addr         tmp;
143         unsigned long    symnum;
144
145         where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
146         symnum = ELF_R_SYM(rel->r_info);
147
148         switch (ELF_R_TYPE(rel->r_info)) {
149         case R_ARM_NONE:
150                 break;
151                 
152 #if 1 /* XXX should not occur */
153         case R_ARM_PC24: {      /* word32 S - P + A */
154                 Elf32_Sword addend;
155                 
156                 /*
157                  * Extract addend and sign-extend if needed.
158                  */
159                 addend = *where;
160                 if (addend & 0x00800000)
161                         addend |= 0xff000000;
162                 
163                 def = find_symdef(symnum, obj, &defobj, flags, cache,
164                     lockstate);
165                 if (def == NULL)
166                                 return -1;
167                         tmp = (Elf_Addr)obj->relocbase + def->st_value
168                             - (Elf_Addr)where + (addend << 2);
169                         if ((tmp & 0xfe000000) != 0xfe000000 &&
170                             (tmp & 0xfe000000) != 0) {
171                                 _rtld_error(
172                                 "%s: R_ARM_PC24 relocation @ %p to %s failed "
173                                 "(displacement %ld (%#lx) out of range)",
174                                     obj->path, where,
175                                     obj->strtab + obj->symtab[symnum].st_name,
176                                     (long) tmp, (long) tmp);
177                                 return -1;
178                         }
179                         tmp >>= 2;
180                         *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
181                         dbg("PC24 %s in %s --> %p @ %p in %s",
182                             obj->strtab + obj->symtab[symnum].st_name,
183                             obj->path, (void *)*where, where, defobj->path);
184                         break;
185                 }
186 #endif
187
188                 case R_ARM_ABS32:       /* word32 B + S + A */
189                 case R_ARM_GLOB_DAT:    /* word32 B + S */
190                         def = find_symdef(symnum, obj, &defobj, flags, cache,
191                             lockstate);
192                         if (def == NULL)
193                                 return -1;
194                         if (__predict_true(RELOC_ALIGNED_P(where))) {
195                                 tmp =  *where + (Elf_Addr)defobj->relocbase +
196                                     def->st_value;
197                                 *where = tmp;
198                         } else {
199                                 tmp = load_ptr(where) +
200                                     (Elf_Addr)defobj->relocbase +
201                                     def->st_value;
202                                 store_ptr(where, tmp);
203                         }
204                         dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
205                             obj->strtab + obj->symtab[symnum].st_name,
206                             obj->path, (void *)tmp, where, defobj->path);
207                         break;
208
209                 case R_ARM_RELATIVE:    /* word32 B + A */
210                         if (__predict_true(RELOC_ALIGNED_P(where))) {
211                                 tmp = *where + (Elf_Addr)obj->relocbase;
212                                 *where = tmp;
213                         } else {
214                                 tmp = load_ptr(where) +
215                                     (Elf_Addr)obj->relocbase;
216                                 store_ptr(where, tmp);
217                         }
218                         dbg("RELATIVE in %s --> %p", obj->path,
219                             (void *)tmp);
220                         break;
221
222                 case R_ARM_COPY:
223                         /*
224                          * These are deferred until all other relocations have
225                          * been done.  All we do here is make sure that the
226                          * COPY relocation is not in a shared library.  They
227                          * are allowed only in executable files.
228                          */
229                         if (!obj->mainprog) {
230                                 _rtld_error(
231                         "%s: Unexpected R_COPY relocation in shared library",
232                                     obj->path);
233                                 return -1;
234                         }
235                         dbg("COPY (avoid in main)");
236                         break;
237
238                 default:
239                         dbg("sym = %lu, type = %lu, offset = %p, "
240                             "contents = %p, symbol = %s",
241                             symnum, (u_long)ELF_R_TYPE(rel->r_info),
242                             (void *)rel->r_offset, (void *)load_ptr(where),
243                             obj->strtab + obj->symtab[symnum].st_name);
244                         _rtld_error("%s: Unsupported relocation type %ld "
245                             "in non-PLT relocations\n",
246                             obj->path, (u_long) ELF_R_TYPE(rel->r_info));
247                         return -1;
248         }
249         return 0;
250 }
251
252 /*
253  *  * Process non-PLT relocations
254  *   */
255 int
256 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
257     RtldLockState *lockstate)
258 {
259         const Elf_Rel *rellim;
260         const Elf_Rel *rel;
261         SymCache *cache;
262         int r = -1;
263         
264         /* The relocation for the dynamic loader has already been done. */
265         if (obj == obj_rtld)
266                 return (0);
267         /*
268          * The dynamic loader may be called from a thread, we have
269          * limited amounts of stack available so we cannot use alloca().
270          */
271         cache = calloc(obj->nchains, sizeof(SymCache));
272         /* No need to check for NULL here */
273
274         rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
275         for (rel = obj->rel; rel < rellim; rel++) {
276                 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0)
277                         goto done;
278         }
279         r = 0;
280 done:
281         if (cache != NULL)
282                 free(cache);
283         return (r);
284 }
285
286 /*
287  *  * Process the PLT relocations.
288  *   */
289 int
290 reloc_plt(Obj_Entry *obj)
291 {
292         const Elf_Rel *rellim;
293         const Elf_Rel *rel;
294                 
295         rellim = (const Elf_Rel *)((char *)obj->pltrel +
296             obj->pltrelsize);
297         for (rel = obj->pltrel;  rel < rellim;  rel++) {
298                 Elf_Addr *where;
299
300                 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
301                 
302                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
303                 *where += (Elf_Addr )obj->relocbase;
304         }
305         
306         return (0);
307 }
308
309 /*
310  *  * LD_BIND_NOW was set - force relocation for all jump slots
311  *   */
312 int
313 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
314 {
315         const Obj_Entry *defobj;
316         const Elf_Rel *rellim;
317         const Elf_Rel *rel;
318         const Elf_Sym *def;
319         Elf_Addr *where;
320         Elf_Addr target;
321         
322         rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
323         for (rel = obj->pltrel; rel < rellim; rel++) {
324                 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
325                 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
326                 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
327                     SYMLOOK_IN_PLT | flags, NULL, lockstate);
328                 if (def == NULL) {
329                         dbg("reloc_jmpslots: sym not found");
330                         return (-1);
331                 }
332                 
333                 target = (Elf_Addr)(defobj->relocbase + def->st_value);         
334                 reloc_jmpslot(where, target, defobj, obj,
335                     (const Elf_Rel *) rel);
336         }
337         
338         obj->jmpslots_done = true;
339         
340         return (0);
341 }
342
343 int
344 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
345 {
346
347         /* XXX not implemented */
348         return (0);
349 }
350
351 int
352 reloc_gnu_ifunc(Obj_Entry *obj, int flags,
353     struct Struct_RtldLockState *lockstate)
354 {
355
356         /* XXX not implemented */
357         return (0);
358 }
359
360 Elf_Addr
361 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
362                 const Obj_Entry *obj, const Elf_Rel *rel)
363 {
364
365         assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
366
367         if (*where != target)
368                 *where = target;
369
370         return target;
371 }
372
373 void
374 allocate_initial_tls(Obj_Entry *objs)
375 {
376         
377 }
378
379 void *
380 __tls_get_addr(tls_index* ti)
381 {
382         return (NULL);
383 }