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