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