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