Deleted Added
full compact
reloc.c (153515) reloc.c (208256)
1/* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
2
3#include <sys/cdefs.h>
1/* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */
2
3#include <sys/cdefs.h>
4__FBSDID("$FreeBSD: head/libexec/rtld-elf/arm/reloc.c 153515 2005-12-18 19:43:33Z kan $");
4__FBSDID("$FreeBSD: head/libexec/rtld-elf/arm/reloc.c 208256 2010-05-18 08:55:23Z rdivacky $");
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
16void
17init_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
25int
26do_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
70void _rtld_bind_start(void);
71void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
72
73int open();
74int _open();
75void
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
108static __inline Elf_Addr
109load_ptr(void *where)
110{
111 Elf_Addr res;
112
113 memcpy(&res, where, sizeof(res));
114
115 return (res);
116}
117
118static __inline void
119store_ptr(void *where, Elf_Addr val)
120{
121
122 memcpy(where, &val, sizeof(val));
123}
124
125static int
126reloc_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 * */
242int
243reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
244{
245 const Elf_Rel *rellim;
246 const Elf_Rel *rel;
247 SymCache *cache;
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
16void
17init_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
25int
26do_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
70void _rtld_bind_start(void);
71void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
72
73int open();
74int _open();
75void
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
108static __inline Elf_Addr
109load_ptr(void *where)
110{
111 Elf_Addr res;
112
113 memcpy(&res, where, sizeof(res));
114
115 return (res);
116}
117
118static __inline void
119store_ptr(void *where, Elf_Addr val)
120{
121
122 memcpy(where, &val, sizeof(val));
123}
124
125static int
126reloc_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 * */
242int
243reloc_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 */
248 int r = -1;
249
250 /* The relocation for the dynamic loader has already been done. */
251 if (obj == obj_rtld)
252 return (0);
253 /*
254 * The dynamic loader may be called from a thread, we have
255 * limited amounts of stack available so we cannot use alloca().
256 */
258 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
259 if (cache == MAP_FAILED)
260 cache = NULL;
261
257 cache = calloc(obj->nchains, sizeof(SymCache));
258 /* No need to check for NULL here */
259
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;
268done:
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;
266done:
269 if (cache) {
270 munmap(cache, bytes);
271 }
267 if (cache != NULL)
268 free(cache);
272 return (r);
273}
274
275/*
276 * * Process the PLT relocations.
277 * */
278int
279reloc_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 * */
301int
302reloc_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
332Elf_Addr
333reloc_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
345void
346allocate_initial_tls(Obj_Entry *objs)
347{
348
349}
350
351void *
352__tls_get_addr(tls_index* ti)
353{
354 return (NULL);
355}
269 return (r);
270}
271
272/*
273 * * Process the PLT relocations.
274 * */
275int
276reloc_plt(Obj_Entry *obj)
277{
278 const Elf_Rel *rellim;
279 const Elf_Rel *rel;
280
281 rellim = (const Elf_Rel *)((char *)obj->pltrel +
282 obj->pltrelsize);
283 for (rel = obj->pltrel; rel < rellim; rel++) {
284 Elf_Addr *where;
285
286 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
287
288 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
289 *where += (Elf_Addr )obj->relocbase;
290 }
291
292 return (0);
293}
294
295/*
296 * * LD_BIND_NOW was set - force relocation for all jump slots
297 * */
298int
299reloc_jmpslots(Obj_Entry *obj)
300{
301 const Obj_Entry *defobj;
302 const Elf_Rel *rellim;
303 const Elf_Rel *rel;
304 const Elf_Sym *def;
305 Elf_Addr *where;
306 Elf_Addr target;
307
308 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
309 for (rel = obj->pltrel; rel < rellim; rel++) {
310 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
311 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
312 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
313 true, NULL);
314 if (def == NULL) {
315 dbg("reloc_jmpslots: sym not found");
316 return (-1);
317 }
318
319 target = (Elf_Addr)(defobj->relocbase + def->st_value);
320 reloc_jmpslot(where, target, defobj, obj,
321 (const Elf_Rel *) rel);
322 }
323
324 obj->jmpslots_done = true;
325
326 return (0);
327}
328
329Elf_Addr
330reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
331 const Obj_Entry *obj, const Elf_Rel *rel)
332{
333
334 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
335
336 if (*where != target)
337 *where = target;
338
339 return target;
340}
341
342void
343allocate_initial_tls(Obj_Entry *objs)
344{
345
346}
347
348void *
349__tls_get_addr(tls_index* ti)
350{
351 return (NULL);
352}