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