reloc.c revision 153503
1/*-
2 * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * $FreeBSD: head/libexec/rtld-elf/ia64/reloc.c 153503 2005-12-18 01:38:26Z marcel $
26 */
27
28/*
29 * Dynamic linker for ELF.
30 *
31 * John Polstra <jdp@polstra.com>.
32 */
33
34#include <sys/param.h>
35#include <sys/mman.h>
36#include <machine/ia64_cpu.h>
37
38#include <dlfcn.h>
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <stdarg.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47
48#include "debug.h"
49#include "rtld.h"
50
51extern Elf_Dyn _DYNAMIC;
52
53/*
54 * Macros for loading/storing unaligned 64-bit values.  These are
55 * needed because relocations can point to unaligned data.  This
56 * occurs in the DWARF2 exception frame tables generated by the
57 * compiler, for instance.
58 *
59 * We don't use these when relocating jump slots and GOT entries,
60 * since they are guaranteed to be aligned.
61 *
62 * XXX dfr stub for now.
63 */
64#define load64(p)	(*(u_int64_t *) (p))
65#define store64(p, v)	(*(u_int64_t *) (p) = (v))
66
67/* Allocate an @fptr. */
68
69#define FPTR_CHUNK_SIZE		64
70
71struct fptr_chunk {
72	struct fptr fptrs[FPTR_CHUNK_SIZE];
73};
74
75static struct fptr_chunk first_chunk;
76static struct fptr_chunk *current_chunk = &first_chunk;
77static struct fptr *next_fptr = &first_chunk.fptrs[0];
78static struct fptr *last_fptr = &first_chunk.fptrs[FPTR_CHUNK_SIZE];
79
80/*
81 * We use static storage initially so that we don't have to call
82 * malloc during init_rtld().
83 */
84static struct fptr *
85alloc_fptr(Elf_Addr target, Elf_Addr gp)
86{
87	struct fptr* fptr;
88
89	if (next_fptr == last_fptr) {
90		current_chunk = malloc(sizeof(struct fptr_chunk));
91		next_fptr = &current_chunk->fptrs[0];
92		last_fptr = &current_chunk->fptrs[FPTR_CHUNK_SIZE];
93	}
94	fptr = next_fptr;
95	next_fptr++;
96	fptr->target = target;
97	fptr->gp = gp;
98	return fptr;
99}
100
101static struct fptr **
102alloc_fptrs(Obj_Entry *obj, bool mapped)
103{
104	struct fptr **fptrs;
105	size_t fbytes;
106
107	fbytes = obj->nchains * sizeof(struct fptr *);
108
109	/*
110	 * Avoid malloc, if requested. Happens when relocating
111	 * rtld itself on startup.
112	 */
113	if (mapped) {
114		fptrs = mmap(NULL, fbytes, PROT_READ|PROT_WRITE,
115	    	    MAP_ANON, -1, 0);
116		if (fptrs == MAP_FAILED)
117			fptrs = NULL;
118	} else {
119		fptrs = malloc(fbytes);
120		if (fptrs != NULL)
121 			memset(fptrs, 0, fbytes);
122	}
123
124	/*
125	 * This assertion is necessary to guarantee function pointer
126	 * uniqueness
127 	 */
128	assert(fptrs != NULL);
129
130	return (obj->priv = fptrs);
131}
132
133static void
134free_fptrs(Obj_Entry *obj, bool mapped)
135{
136	struct fptr **fptrs;
137	size_t fbytes;
138
139	fptrs  = obj->priv;
140	if (fptrs == NULL)
141		return;
142
143	fbytes = obj->nchains * sizeof(struct fptr *);
144	if (mapped)
145		munmap(fptrs, fbytes);
146	else
147		free(fptrs);
148	obj->priv = NULL;
149}
150
151/* Relocate a non-PLT object with addend. */
152static int
153reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
154		  SymCache *cache)
155{
156	struct fptr **fptrs;
157	Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
158
159	switch (ELF_R_TYPE(rela->r_info)) {
160	case R_IA64_REL64LSB:
161		/*
162		 * We handle rtld's relocations in rtld_start.S
163		 */
164		if (obj != obj_rtld)
165			store64(where,
166				load64(where) + (Elf_Addr) obj->relocbase);
167		break;
168
169	case R_IA64_DIR64LSB: {
170		const Elf_Sym *def;
171		const Obj_Entry *defobj;
172		Elf_Addr target;
173
174		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
175				  false, cache);
176		if (def == NULL)
177			return -1;
178
179		target = (def->st_shndx != SHN_UNDEF)
180		    ? (Elf_Addr)(defobj->relocbase + def->st_value) : 0;
181		store64(where, target + rela->r_addend);
182		break;
183	}
184
185	case R_IA64_FPTR64LSB: {
186		/*
187		 * We have to make sure that all @fptr references to
188		 * the same function are identical so that code can
189		 * compare function pointers.
190		 */
191		const Elf_Sym *def;
192		const Obj_Entry *defobj;
193		struct fptr *fptr = 0;
194		Elf_Addr target, gp;
195		int sym_index;
196
197		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
198				  false, cache);
199		if (def == NULL)
200			return -1;
201
202		if (def->st_shndx != SHN_UNDEF) {
203			target = (Elf_Addr)(defobj->relocbase + def->st_value);
204			gp = (Elf_Addr)defobj->pltgot;
205
206			/* rtld is allowed to reference itself only */
207			assert(!obj->rtld || obj == defobj);
208			fptrs = defobj->priv;
209			if (fptrs == NULL)
210				fptrs = alloc_fptrs((Obj_Entry *) defobj,
211				    obj->rtld);
212
213			sym_index = def - defobj->symtab;
214
215			/*
216			 * Find the @fptr, using fptrs as a helper.
217			 */
218			if (fptrs)
219				fptr = fptrs[sym_index];
220			if (!fptr) {
221				fptr = alloc_fptr(target, gp);
222				if (fptrs)
223					fptrs[sym_index] = fptr;
224			}
225		} else
226			fptr = NULL;
227
228		store64(where, (Elf_Addr)fptr);
229		break;
230	}
231
232	case R_IA64_IPLTLSB: {
233		/*
234		 * Relocation typically used to populate C++ virtual function
235		 * tables. It creates a 128-bit function descriptor at the
236		 * specified memory address.
237		 */
238		const Elf_Sym *def;
239		const Obj_Entry *defobj;
240		struct fptr *fptr;
241		Elf_Addr target, gp;
242
243		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
244				  false, cache);
245		if (def == NULL)
246			return -1;
247
248		if (def->st_shndx != SHN_UNDEF) {
249			target = (Elf_Addr)(defobj->relocbase + def->st_value);
250			gp = (Elf_Addr)defobj->pltgot;
251		} else {
252			target = 0;
253			gp = 0;
254		}
255
256		fptr = (void*)where;
257		store64(&fptr->target, target);
258		store64(&fptr->gp, gp);
259		break;
260	}
261
262	case R_IA64_DTPMOD64LSB: {
263		const Elf_Sym *def;
264		const Obj_Entry *defobj;
265
266		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
267				  false, cache);
268		if (def == NULL)
269			return -1;
270
271		store64(where, defobj->tlsindex);
272		break;
273	}
274
275	case R_IA64_DTPREL64LSB: {
276		const Elf_Sym *def;
277		const Obj_Entry *defobj;
278
279		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
280				  false, cache);
281		if (def == NULL)
282			return -1;
283
284		store64(where, def->st_value + rela->r_addend);
285		break;
286	}
287
288	case R_IA64_TPREL64LSB: {
289		const Elf_Sym *def;
290		const Obj_Entry *defobj;
291
292		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
293				  false, cache);
294		if (def == NULL)
295			return -1;
296
297		/*
298		 * We lazily allocate offsets for static TLS as we
299		 * see the first relocation that references the
300		 * TLS block. This allows us to support (small
301		 * amounts of) static TLS in dynamically loaded
302		 * modules. If we run out of space, we generate an
303		 * error.
304		 */
305		if (!defobj->tls_done) {
306			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
307				_rtld_error("%s: No space available for static "
308				    "Thread Local Storage", obj->path);
309				return -1;
310			}
311		}
312
313		store64(where, defobj->tlsoffset + def->st_value + rela->r_addend);
314		break;
315	}
316
317	case R_IA64_NONE:
318		break;
319
320	default:
321		_rtld_error("%s: Unsupported relocation type %u"
322			    " in non-PLT relocations\n", obj->path,
323			    (unsigned int)ELF_R_TYPE(rela->r_info));
324		return -1;
325	}
326
327	return(0);
328}
329
330/* Process the non-PLT relocations. */
331int
332reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
333{
334	const Elf_Rel *rellim;
335	const Elf_Rel *rel;
336	const Elf_Rela *relalim;
337	const Elf_Rela *rela;
338	SymCache *cache;
339	int bytes = obj->nchains * sizeof(SymCache);
340	int r = -1;
341
342	/*
343	 * The dynamic loader may be called from a thread, we have
344	 * limited amounts of stack available so we cannot use alloca().
345	 */
346	cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
347	if (cache == MAP_FAILED)
348		cache = NULL;
349
350	/* Perform relocations without addend if there are any: */
351	rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
352	for (rel = obj->rel;  obj->rel != NULL && rel < rellim;  rel++) {
353		Elf_Rela locrela;
354
355		locrela.r_info = rel->r_info;
356		locrela.r_offset = rel->r_offset;
357		locrela.r_addend = 0;
358		if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache))
359			goto done;
360	}
361
362	/* Perform relocations with addend if there are any: */
363	relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
364	for (rela = obj->rela;  obj->rela != NULL && rela < relalim;  rela++) {
365		if (reloc_non_plt_obj(obj_rtld, obj, rela, cache))
366			goto done;
367	}
368
369	r = 0;
370done:
371	if (cache)
372		munmap(cache, bytes);
373
374	/*
375	 * Release temporarily mapped fptrs if relocating
376	 * rtld object itself. A new table will be created
377	 * in make_function_pointer using malloc when needed.
378	 */
379	if (obj->rtld && obj->priv)
380		free_fptrs(obj, true);
381
382	return (r);
383}
384
385/* Process the PLT relocations. */
386int
387reloc_plt(Obj_Entry *obj)
388{
389	/* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
390	if (obj->pltrelsize != 0) {
391		const Elf_Rel *rellim;
392		const Elf_Rel *rel;
393
394		rellim = (const Elf_Rel *)
395			((char *)obj->pltrel + obj->pltrelsize);
396		for (rel = obj->pltrel;  rel < rellim;  rel++) {
397			Elf_Addr *where;
398
399			assert(ELF_R_TYPE(rel->r_info) == R_IA64_IPLTLSB);
400
401			/* Relocate the @fptr pointing into the PLT. */
402			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
403			*where += (Elf_Addr)obj->relocbase;
404		}
405	} else {
406		const Elf_Rela *relalim;
407		const Elf_Rela *rela;
408
409		relalim = (const Elf_Rela *)
410			((char *)obj->pltrela + obj->pltrelasize);
411		for (rela = obj->pltrela;  rela < relalim;  rela++) {
412			Elf_Addr *where;
413
414			assert(ELF_R_TYPE(rela->r_info) == R_IA64_IPLTLSB);
415
416			/* Relocate the @fptr pointing into the PLT. */
417			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
418			*where += (Elf_Addr)obj->relocbase;
419		}
420	}
421	return 0;
422}
423
424/* Relocate the jump slots in an object. */
425int
426reloc_jmpslots(Obj_Entry *obj)
427{
428	if (obj->jmpslots_done)
429		return 0;
430	/* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
431	if (obj->pltrelsize != 0) {
432		const Elf_Rel *rellim;
433		const Elf_Rel *rel;
434
435		rellim = (const Elf_Rel *)
436			((char *)obj->pltrel + obj->pltrelsize);
437		for (rel = obj->pltrel;  rel < rellim;  rel++) {
438			Elf_Addr *where;
439			const Elf_Sym *def;
440			const Obj_Entry *defobj;
441
442			assert(ELF_R_TYPE(rel->r_info) == R_IA64_IPLTLSB);
443			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
444			def = find_symdef(ELF_R_SYM(rel->r_info), obj,
445					  &defobj, true, NULL);
446			if (def == NULL)
447				return -1;
448			reloc_jmpslot(where,
449				      (Elf_Addr)(defobj->relocbase
450						 + def->st_value),
451				      defobj, obj, rel);
452		}
453	} else {
454		const Elf_Rela *relalim;
455		const Elf_Rela *rela;
456
457		relalim = (const Elf_Rela *)
458			((char *)obj->pltrela + obj->pltrelasize);
459		for (rela = obj->pltrela;  rela < relalim;  rela++) {
460			Elf_Addr *where;
461			const Elf_Sym *def;
462			const Obj_Entry *defobj;
463
464			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
465			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
466					  &defobj, true, NULL);
467			if (def == NULL)
468				return -1;
469			reloc_jmpslot(where,
470				      (Elf_Addr)(defobj->relocbase
471						 + def->st_value),
472				      defobj, obj, (Elf_Rel *)rela);
473		}
474	}
475	obj->jmpslots_done = true;
476	return 0;
477}
478
479/* Fixup the jump slot at "where" to transfer control to "target". */
480Elf_Addr
481reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *obj,
482	      const Obj_Entry *refobj, const Elf_Rel *rel)
483{
484	Elf_Addr stubaddr;
485
486	dbg(" reloc_jmpslot: where=%p, target=%p, gp=%p",
487	    (void *)where, (void *)target, (void *)obj->pltgot);
488	stubaddr = *where;
489	if (stubaddr != target) {
490
491		/*
492		 * Point this @fptr directly at the target. Update the
493		 * gp value first so that we don't break another cpu
494		 * which is currently executing the PLT entry.
495		 */
496		where[1] = (Elf_Addr) obj->pltgot;
497		ia64_mf();
498		where[0] = target;
499		ia64_mf();
500	}
501
502	/*
503	 * The caller needs an @fptr for the adjusted entry. The PLT
504	 * entry serves this purpose nicely.
505	 */
506	return (Elf_Addr) where;
507}
508
509/*
510 * XXX ia64 doesn't seem to have copy relocations.
511 *
512 * Returns 0 on success, -1 on failure.
513 */
514int
515do_copy_relocations(Obj_Entry *dstobj)
516{
517
518	return 0;
519}
520
521/*
522 * Return the @fptr representing a given function symbol.
523 */
524void *
525make_function_pointer(const Elf_Sym *sym, const Obj_Entry *obj)
526{
527	struct fptr **fptrs = obj->priv;
528	int index = sym - obj->symtab;
529
530	if (!fptrs) {
531		/*
532		 * This should only happen for something like
533		 * dlsym("dlopen"). Actually, I'm not sure it can ever
534		 * happen.
535		 */
536		fptrs = alloc_fptrs((Obj_Entry *) obj, false);
537	}
538	if (!fptrs[index]) {
539		Elf_Addr target, gp;
540		target = (Elf_Addr) (obj->relocbase + sym->st_value);
541		gp = (Elf_Addr) obj->pltgot;
542		fptrs[index] = alloc_fptr(target, gp);
543	}
544	return fptrs[index];
545}
546
547void
548call_initfini_pointer(const Obj_Entry *obj, Elf_Addr target)
549{
550	struct fptr fptr;
551
552	fptr.gp = (Elf_Addr) obj->pltgot;
553	fptr.target = target;
554	dbg(" initfini: target=%p, gp=%p",
555	    (void *) fptr.target, (void *) fptr.gp);
556	((InitFunc) &fptr)();
557}
558
559/* Initialize the special PLT entries. */
560void
561init_pltgot(Obj_Entry *obj)
562{
563	const Elf_Dyn *dynp;
564	Elf_Addr *pltres = 0;
565
566	/*
567	 * When there are no PLT relocations, the DT_IA64_PLT_RESERVE entry
568	 * is bogus. Do not setup the BOR pointers in that case. An example
569	 * of where this happens is /usr/lib/libxpg4.so.3.
570	 */
571	if (obj->pltrelasize == 0 && obj->pltrelsize == 0)
572		return;
573
574	/*
575	 * Find the PLT RESERVE section.
576	 */
577	for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
578		if (dynp->d_tag == DT_IA64_PLT_RESERVE)
579			pltres = (u_int64_t *)
580				(obj->relocbase + dynp->d_un.d_ptr);
581	}
582	if (!pltres)
583		errx(1, "Can't find DT_IA64_PLT_RESERVE entry");
584
585	/*
586	 * The PLT RESERVE section is used to get values to pass to
587	 * _rtld_bind when lazy binding.
588	 */
589	pltres[0] = (Elf_Addr) obj;
590	pltres[1] = FPTR_TARGET(_rtld_bind_start);
591	pltres[2] = FPTR_GP(_rtld_bind_start);
592}
593
594void
595allocate_initial_tls(Obj_Entry *list)
596{
597    register Elf_Addr** tp __asm__("r13");
598
599    /*
600     * Fix the size of the static TLS block by using the maximum
601     * offset allocated so far and adding a bit for dynamic modules to
602     * use.
603     */
604    tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
605
606    tp = allocate_tls(list, 0, 16, 16);
607}
608
609void *__tls_get_addr(unsigned long module, unsigned long offset)
610{
611    register Elf_Addr** tp __asm__("r13");
612
613    return tls_get_addr_common(tp, module, offset);
614}
615