reloc.c revision 331205
1/*	$NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $	*/
2
3#include <sys/cdefs.h>
4__FBSDID("$FreeBSD: stable/11/libexec/rtld-elf/arm/reloc.c 331205 2018-03-19 14:28:20Z marius $");
5#include <sys/param.h>
6#include <sys/stat.h>
7#include <sys/mman.h>
8
9#include <errno.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "machine/sysarch.h"
16
17#include "debug.h"
18#include "rtld.h"
19#include "paths.h"
20
21void
22arm_abi_variant_hook(Elf_Auxinfo **aux_info)
23{
24	Elf_Word ehdr;
25	struct stat sb;
26
27	/*
28	 * If we're running an old kernel that doesn't provide any data fail
29	 * safe by doing nothing.
30	 */
31	if (aux_info[AT_EHDRFLAGS] == NULL)
32		return;
33	ehdr = aux_info[AT_EHDRFLAGS]->a_un.a_val;
34
35	/*
36	 * Hard float ABI binaries are the default, and use the default paths
37	 * and such.
38	 */
39	if ((ehdr & EF_ARM_VFP_FLOAT) != 0)
40		return;
41
42	/*
43	 * If there's no /usr/libsoft, then we don't have a system with both
44	 * hard and soft float. In that case, hope for the best and just
45	 * return. Such systems are required to have all soft or all hard
46	 * float ABI binaries and libraries. This is, at best, a transition
47	 * compatibility hack. Once we're fully hard-float, this should
48	 * be removed.
49	 */
50	if (stat("/usr/libsoft", &sb) != 0 || !S_ISDIR(sb.st_mode))
51		return;
52
53	/*
54	 * This is a soft float ABI binary. We need to use the soft float
55	 * settings.
56	 */
57	ld_elf_hints_default = _PATH_SOFT_ELF_HINTS;
58	ld_path_libmap_conf = _PATH_SOFT_LIBMAP_CONF;
59	ld_path_rtld = _PATH_SOFT_RTLD;
60	ld_standard_library_path = SOFT_STANDARD_LIBRARY_PATH;
61	ld_env_prefix = LD_SOFT_;
62}
63
64void
65init_pltgot(Obj_Entry *obj)
66{
67	if (obj->pltgot != NULL) {
68		obj->pltgot[1] = (Elf_Addr) obj;
69		obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
70	}
71}
72
73int
74do_copy_relocations(Obj_Entry *dstobj)
75{
76	const Elf_Rel *rellim;
77	const Elf_Rel *rel;
78
79	assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */
80
81   	rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
82	for (rel = dstobj->rel;  rel < rellim;  rel++) {
83		if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
84	    		void *dstaddr;
85			const Elf_Sym *dstsym;
86			const char *name;
87			size_t size;
88			const void *srcaddr;
89			const Elf_Sym *srcsym;
90			const Obj_Entry *srcobj, *defobj;
91			SymLook req;
92			int res;
93
94			dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
95			dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
96			name = dstobj->strtab + dstsym->st_name;
97			size = dstsym->st_size;
98
99			symlook_init(&req, name);
100			req.ventry = fetch_ventry(dstobj,
101			    ELF_R_SYM(rel->r_info));
102			req.flags = SYMLOOK_EARLY;
103
104			for (srcobj = globallist_next(dstobj); srcobj != NULL;
105			    srcobj = globallist_next(srcobj)) {
106				res = symlook_obj(&req, srcobj);
107				if (res == 0) {
108					srcsym = req.sym_out;
109					defobj = req.defobj_out;
110					break;
111				}
112			}
113			if (srcobj == NULL) {
114				_rtld_error(
115"Undefined symbol \"%s\" referenced from COPY relocation in %s",
116				    name, dstobj->path);
117				return (-1);
118			}
119
120			srcaddr = (const void *)(defobj->relocbase +
121			    srcsym->st_value);
122			memcpy(dstaddr, srcaddr, size);
123		}
124	}
125	return 0;
126}
127
128void _rtld_bind_start(void);
129void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
130
131int open();
132int _open();
133void
134_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
135{
136	const Elf_Rel *rel = NULL, *rellim;
137	Elf_Addr relsz = 0;
138	Elf_Addr *where;
139	uint32_t size;
140
141	for (; dynp->d_tag != DT_NULL; dynp++) {
142		switch (dynp->d_tag) {
143		case DT_REL:
144			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
145			break;
146		case DT_RELSZ:
147			relsz = dynp->d_un.d_val;
148			break;
149		}
150	}
151	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
152	size = (rellim - 1)->r_offset - rel->r_offset;
153	for (; rel < rellim; rel++) {
154		where = (Elf_Addr *)(relocbase + rel->r_offset);
155
156		*where += (Elf_Addr)relocbase;
157	}
158}
159/*
160 * It is possible for the compiler to emit relocations for unaligned data.
161 * We handle this situation with these inlines.
162 */
163#define	RELOC_ALIGNED_P(x) \
164	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
165
166static __inline Elf_Addr
167load_ptr(void *where)
168{
169	Elf_Addr res;
170
171	memcpy(&res, where, sizeof(res));
172
173	return (res);
174}
175
176static __inline void
177store_ptr(void *where, Elf_Addr val)
178{
179
180	memcpy(where, &val, sizeof(val));
181}
182
183static int
184reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
185    int flags, RtldLockState *lockstate)
186{
187	Elf_Addr        *where;
188	const Elf_Sym   *def;
189	const Obj_Entry *defobj;
190	Elf_Addr         tmp;
191	unsigned long	 symnum;
192
193	where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
194	symnum = ELF_R_SYM(rel->r_info);
195
196	switch (ELF_R_TYPE(rel->r_info)) {
197	case R_ARM_NONE:
198		break;
199
200#if 1 /* XXX should not occur */
201	case R_ARM_PC24: {	/* word32 S - P + A */
202		Elf32_Sword addend;
203
204		/*
205		 * Extract addend and sign-extend if needed.
206		 */
207		addend = *where;
208		if (addend & 0x00800000)
209			addend |= 0xff000000;
210
211		def = find_symdef(symnum, obj, &defobj, flags, cache,
212		    lockstate);
213		if (def == NULL)
214				return -1;
215			tmp = (Elf_Addr)obj->relocbase + def->st_value
216			    - (Elf_Addr)where + (addend << 2);
217			if ((tmp & 0xfe000000) != 0xfe000000 &&
218			    (tmp & 0xfe000000) != 0) {
219				_rtld_error(
220				"%s: R_ARM_PC24 relocation @ %p to %s failed "
221				"(displacement %ld (%#lx) out of range)",
222				    obj->path, where,
223				    obj->strtab + obj->symtab[symnum].st_name,
224				    (long) tmp, (long) tmp);
225				return -1;
226			}
227			tmp >>= 2;
228			*where = (*where & 0xff000000) | (tmp & 0x00ffffff);
229			dbg("PC24 %s in %s --> %p @ %p in %s",
230			    obj->strtab + obj->symtab[symnum].st_name,
231			    obj->path, (void *)*where, where, defobj->path);
232			break;
233		}
234#endif
235
236		case R_ARM_ABS32:	/* word32 B + S + A */
237		case R_ARM_GLOB_DAT:	/* word32 B + S */
238			def = find_symdef(symnum, obj, &defobj, flags, cache,
239			    lockstate);
240			if (def == NULL)
241				return -1;
242			if (__predict_true(RELOC_ALIGNED_P(where))) {
243				tmp =  *where + (Elf_Addr)defobj->relocbase +
244				    def->st_value;
245				*where = tmp;
246			} else {
247				tmp = load_ptr(where) +
248				    (Elf_Addr)defobj->relocbase +
249				    def->st_value;
250				store_ptr(where, tmp);
251			}
252			dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
253			    obj->strtab + obj->symtab[symnum].st_name,
254			    obj->path, (void *)tmp, where, defobj->path);
255			break;
256
257		case R_ARM_RELATIVE:	/* word32 B + A */
258			if (__predict_true(RELOC_ALIGNED_P(where))) {
259				tmp = *where + (Elf_Addr)obj->relocbase;
260				*where = tmp;
261			} else {
262				tmp = load_ptr(where) +
263				    (Elf_Addr)obj->relocbase;
264				store_ptr(where, tmp);
265			}
266			dbg("RELATIVE in %s --> %p", obj->path,
267			    (void *)tmp);
268			break;
269
270		case R_ARM_COPY:
271			/*
272			 * These are deferred until all other relocations have
273			 * been done.  All we do here is make sure that the
274			 * COPY relocation is not in a shared library.  They
275			 * are allowed only in executable files.
276			 */
277			if (!obj->mainprog) {
278				_rtld_error(
279			"%s: Unexpected R_COPY relocation in shared library",
280				    obj->path);
281				return -1;
282			}
283			dbg("COPY (avoid in main)");
284			break;
285
286		case R_ARM_TLS_DTPOFF32:
287			def = find_symdef(symnum, obj, &defobj, flags, cache,
288			    lockstate);
289			if (def == NULL)
290				return -1;
291
292			tmp = (Elf_Addr)(def->st_value);
293			if (__predict_true(RELOC_ALIGNED_P(where)))
294				*where = tmp;
295			else
296				store_ptr(where, tmp);
297
298			dbg("TLS_DTPOFF32 %s in %s --> %p",
299			    obj->strtab + obj->symtab[symnum].st_name,
300			    obj->path, (void *)tmp);
301
302			break;
303		case R_ARM_TLS_DTPMOD32:
304			def = find_symdef(symnum, obj, &defobj, flags, cache,
305			    lockstate);
306			if (def == NULL)
307				return -1;
308
309			tmp = (Elf_Addr)(defobj->tlsindex);
310			if (__predict_true(RELOC_ALIGNED_P(where)))
311				*where = tmp;
312			else
313				store_ptr(where, tmp);
314
315			dbg("TLS_DTPMOD32 %s in %s --> %p",
316			    obj->strtab + obj->symtab[symnum].st_name,
317			    obj->path, (void *)tmp);
318
319			break;
320
321		case R_ARM_TLS_TPOFF32:
322			def = find_symdef(symnum, obj, &defobj, flags, cache,
323			    lockstate);
324			if (def == NULL)
325				return -1;
326
327			if (!defobj->tls_done && allocate_tls_offset(obj))
328				return -1;
329
330			/* XXX: FIXME */
331			tmp = (Elf_Addr)def->st_value + defobj->tlsoffset +
332			    TLS_TCB_SIZE;
333			if (__predict_true(RELOC_ALIGNED_P(where)))
334				*where = tmp;
335			else
336				store_ptr(where, tmp);
337			dbg("TLS_TPOFF32 %s in %s --> %p",
338			    obj->strtab + obj->symtab[symnum].st_name,
339			    obj->path, (void *)tmp);
340			break;
341
342
343		default:
344			dbg("sym = %lu, type = %lu, offset = %p, "
345			    "contents = %p, symbol = %s",
346			    symnum, (u_long)ELF_R_TYPE(rel->r_info),
347			    (void *)rel->r_offset, (void *)load_ptr(where),
348			    obj->strtab + obj->symtab[symnum].st_name);
349			_rtld_error("%s: Unsupported relocation type %ld "
350			    "in non-PLT relocations\n",
351			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
352			return -1;
353	}
354	return 0;
355}
356
357/*
358 *  * Process non-PLT relocations
359 *   */
360int
361reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
362    RtldLockState *lockstate)
363{
364	const Elf_Rel *rellim;
365	const Elf_Rel *rel;
366	SymCache *cache;
367	int r = -1;
368
369	/* The relocation for the dynamic loader has already been done. */
370	if (obj == obj_rtld)
371		return (0);
372	if ((flags & SYMLOOK_IFUNC) != 0)
373		/* XXX not implemented */
374		return (0);
375
376	/*
377 	 * The dynamic loader may be called from a thread, we have
378	 * limited amounts of stack available so we cannot use alloca().
379	 */
380	cache = calloc(obj->dynsymcount, sizeof(SymCache));
381	/* No need to check for NULL here */
382
383	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
384	for (rel = obj->rel; rel < rellim; rel++) {
385		if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0)
386			goto done;
387	}
388	r = 0;
389done:
390	if (cache != NULL)
391		free(cache);
392	return (r);
393}
394
395/*
396 *  * Process the PLT relocations.
397 *   */
398int
399reloc_plt(Obj_Entry *obj)
400{
401	const Elf_Rel *rellim;
402	const Elf_Rel *rel;
403
404	rellim = (const Elf_Rel *)((char *)obj->pltrel +
405	    obj->pltrelsize);
406	for (rel = obj->pltrel;  rel < rellim;  rel++) {
407		Elf_Addr *where;
408
409		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
410
411		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
412		*where += (Elf_Addr )obj->relocbase;
413	}
414
415	return (0);
416}
417
418/*
419 *  * LD_BIND_NOW was set - force relocation for all jump slots
420 *   */
421int
422reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
423{
424	const Obj_Entry *defobj;
425	const Elf_Rel *rellim;
426	const Elf_Rel *rel;
427	const Elf_Sym *def;
428	Elf_Addr *where;
429	Elf_Addr target;
430
431	rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
432	for (rel = obj->pltrel; rel < rellim; rel++) {
433		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
434		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
435		def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
436		    SYMLOOK_IN_PLT | flags, NULL, lockstate);
437		if (def == NULL) {
438			dbg("reloc_jmpslots: sym not found");
439			return (-1);
440		}
441
442		target = (Elf_Addr)(defobj->relocbase + def->st_value);
443		reloc_jmpslot(where, target, defobj, obj,
444		    (const Elf_Rel *) rel);
445	}
446
447	obj->jmpslots_done = true;
448
449	return (0);
450}
451
452int
453reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
454{
455
456	/* XXX not implemented */
457	return (0);
458}
459
460int
461reloc_gnu_ifunc(Obj_Entry *obj, int flags,
462    struct Struct_RtldLockState *lockstate)
463{
464
465	/* XXX not implemented */
466	return (0);
467}
468
469Elf_Addr
470reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
471    const Obj_Entry *obj, const Elf_Rel *rel)
472{
473
474	assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
475
476	if (*where != target && !ld_bind_not)
477		*where = target;
478	return (target);
479}
480
481void
482ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
483{
484
485}
486
487void
488pre_init(void)
489{
490
491}
492
493void
494allocate_initial_tls(Obj_Entry *objs)
495{
496#ifdef ARM_TP_ADDRESS
497	void **_tp = (void **)ARM_TP_ADDRESS;
498#endif
499
500	/*
501	* Fix the size of the static TLS block by using the maximum
502	* offset allocated so far and adding a bit for dynamic modules to
503	* use.
504	*/
505
506	tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
507
508#ifdef ARM_TP_ADDRESS
509	(*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8);
510#else
511	sysarch(ARM_SET_TP, allocate_tls(objs, NULL, TLS_TCB_SIZE, 8));
512#endif
513}
514
515void *
516__tls_get_addr(tls_index* ti)
517{
518	char *p;
519#ifdef ARM_TP_ADDRESS
520	void **_tp = (void **)ARM_TP_ADDRESS;
521
522	p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset);
523#else
524	void *_tp;
525	__asm __volatile("mrc  p15, 0, %0, c13, c0, 3"		\
526	    : "=r" (_tp));
527	p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset);
528#endif
529
530	return (p);
531}
532