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