reloc.c revision 204687
1/*	$NetBSD: mips_reloc.c,v 1.58 2010/01/14 11:57:06 skrll Exp $	*/
2
3/*
4 * Copyright 1997 Michael L. Hitch <mhitch@montana.edu>
5 * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/libexec/rtld-elf/mips/reloc.c 204687 2010-03-04 04:53:05Z imp $");
33
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <sys/endian.h>
37
38#include <stdlib.h>
39#include <string.h>
40
41#include "debug.h"
42#include "rtld.h"
43
44void
45init_pltgot(Obj_Entry *obj)
46{
47	if (obj->pltgot != NULL) {
48		obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
49		/* XXX only if obj->pltgot[1] & 0x80000000 ?? */
50		obj->pltgot[1] |= (Elf_Addr) obj;
51	}
52}
53
54int
55do_copy_relocations(Obj_Entry *dstobj)
56{
57	/* Do nothing */
58	return 0;
59}
60
61void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
62
63/*
64 * It is possible for the compiler to emit relocations for unaligned data.
65 * We handle this situation with these inlines.
66 */
67#if ELFSIZE == 64
68/*
69 * ELF64 MIPS encodes the relocs uniquely.  The first 32-bits of info contain
70 * the symbol index.  The top 32-bits contain three relocation types encoded
71 * in big-endian integer with first relocation in LSB.  This means for little
72 * endian we have to byte swap that interger (r_type).
73 */
74#define	Elf_Sxword			Elf64_Sxword
75#define	ELF_R_NXTTYPE_64_P(r_type)	((((r_type) >> 8) & 0xff) == R_TYPE(64))
76#if BYTE_ORDER == LITTLE_ENDIAN
77#undef ELF_R_SYM
78#undef ELF_R_TYPE
79#define ELF_R_SYM(r_info)		((r_info) & 0xffffffff)
80#define ELF_R_TYPE(r_info)		bswap32((r_info) >> 32)
81#endif
82#else
83#define	ELF_R_NXTTYPE_64_P(r_type)	(0)
84#define	Elf_Sxword			Elf32_Sword
85#endif
86
87static __inline Elf_Sxword
88load_ptr(void *where, size_t len)
89{
90	Elf_Sxword val;
91
92	if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
93#if ELFSIZE == 64
94		if (len == sizeof(Elf_Sxword))
95			return *(Elf_Sxword *)where;
96#endif
97		return *(Elf_Sword *)where;
98	}
99
100	val = 0;
101#if BYTE_ORDER == LITTLE_ENDIAN
102	(void)memcpy(&val, where, len);
103#endif
104#if BYTE_ORDER == BIG_ENDIAN
105	(void)memcpy((uint8_t *)((&val)+1) - len, where, len);
106#endif
107	return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val;
108}
109
110static __inline void
111store_ptr(void *where, Elf_Sxword val, size_t len)
112{
113	if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) {
114#if ELFSIZE == 64
115		if (len == sizeof(Elf_Sxword)) {
116			*(Elf_Sxword *)where = val;
117			return;
118		}
119#endif
120		*(Elf_Sword *)where = val;
121		return;
122	}
123#if BYTE_ORDER == LITTLE_ENDIAN
124	(void)memcpy(where, &val, len);
125#endif
126#if BYTE_ORDER == BIG_ENDIAN
127	(void)memcpy(where, (const uint8_t *)((&val)+1) - len, len);
128#endif
129}
130
131void
132_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
133{
134	const Elf_Rel *rel = 0, *rellim;
135	Elf_Addr relsz = 0;
136	const Elf_Sym *symtab = NULL, *sym;
137	Elf_Addr *where;
138	Elf_Addr *got = NULL;
139	Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
140	size_t i;
141
142	for (; dynp->d_tag != DT_NULL; dynp++) {
143		switch (dynp->d_tag) {
144		case DT_REL:
145			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
146			break;
147		case DT_RELSZ:
148			relsz = dynp->d_un.d_val;
149			break;
150		case DT_SYMTAB:
151			symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
152			break;
153		case DT_PLTGOT:
154			got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
155			break;
156		case DT_MIPS_LOCAL_GOTNO:
157			local_gotno = dynp->d_un.d_val;
158			break;
159		case DT_MIPS_SYMTABNO:
160			symtabno = dynp->d_un.d_val;
161			break;
162		case DT_MIPS_GOTSYM:
163			gotsym = dynp->d_un.d_val;
164			break;
165		}
166	}
167
168	i = (got[1] & 0x80000000) ? 2 : 1;
169	/* Relocate the local GOT entries */
170	got += i;
171	for (; i < local_gotno; i++) {
172		*got++ += relocbase;
173	}
174
175	sym = symtab + gotsym;
176	/* Now do the global GOT entries */
177	for (i = gotsym; i < symtabno; i++) {
178		*got = sym->st_value + relocbase;
179		++sym;
180		++got;
181	}
182
183	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
184	for (; rel < rellim; rel++) {
185		Elf_Word r_symndx, r_type;
186
187		where = (void *)(relocbase + rel->r_offset);
188
189		r_symndx = ELF_R_SYM(rel->r_info);
190		r_type = ELF_R_TYPE(rel->r_info);
191
192		switch (r_type & 0xff) {
193		case R_TYPE(REL32): {
194			const size_t rlen =
195			    ELF_R_NXTTYPE_64_P(r_type)
196				? sizeof(Elf_Sxword)
197				: sizeof(Elf_Sword);
198			Elf_Sxword old = load_ptr(where, rlen);
199			Elf_Sxword val = old;
200#if ELFSIZE == 64
201			assert(r_type == R_TYPE(REL32)
202			    || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
203#endif
204			assert(r_symndx < gotsym);
205			sym = symtab + r_symndx;
206			assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
207			val += relocbase;
208			store_ptr(where, val, sizeof(Elf_Sword));
209			dbg("REL32/L(%p) %p -> %p in <self>",
210			    where, (void *)old, (void *)val);
211			store_ptr(where, val, rlen);
212			break;
213		}
214
215		case R_TYPE(GPREL32):
216		case R_TYPE(NONE):
217			break;
218
219
220		default:
221			abort();
222			break;
223		}
224	}
225}
226
227Elf_Addr
228_mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff)
229{
230        Elf_Addr *got = obj->pltgot;
231        const Elf_Sym *def;
232        const Obj_Entry *defobj;
233        Elf_Addr target;
234
235        def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
236        if (def == NULL)
237		_rtld_error("bind failed no symbol");
238
239        target = (Elf_Addr)(defobj->relocbase + def->st_value);
240        dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p",
241	    obj->path,
242	    reloff, defobj->strtab + def->st_name,
243	    (void *)got[obj->local_gotno + reloff - obj->gotsym],
244	    (void *)target);
245        got[obj->local_gotno + reloff - obj->gotsym] = target;
246	return (Elf_Addr)target;
247}
248
249int
250reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
251{
252	const Elf_Rel *rel;
253	const Elf_Rel *rellim;
254	Elf_Addr *got = obj->pltgot;
255	const Elf_Sym *sym, *def;
256	const Obj_Entry *defobj;
257	Elf_Word i;
258#ifdef SUPPORT_OLD_BROKEN_LD
259	int broken;
260#endif
261
262	/* The relocation for the dynamic loader has already been done. */
263	if (obj == obj_rtld)
264		return (0);
265
266#ifdef SUPPORT_OLD_BROKEN_LD
267	broken = 0;
268	sym = obj->symtab;
269	for (i = 1; i < 12; i++)
270		if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE))
271			broken = 1;
272	dbg("%s: broken=%d", obj->path, broken);
273#endif
274
275	i = (got[1] & 0x80000000) ? 2 : 1;
276
277	/* Relocate the local GOT entries */
278	got += i;
279	dbg("got:%p for %d entries adding %x",
280	    got, obj->local_gotno, (uint32_t)obj->relocbase);
281	for (; i < obj->local_gotno; i++) {
282		*got += (Elf_Addr)obj->relocbase;
283		got++;
284	}
285	sym = obj->symtab + obj->gotsym;
286
287	dbg("got:%p for %d entries",
288	    got, obj->symtabno);
289	/* Now do the global GOT entries */
290	for (i = obj->gotsym; i < obj->symtabno; i++) {
291		dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
292		    sym->st_name + obj->strtab, (u_long) *got);
293
294#ifdef SUPPORT_OLD_BROKEN_LD
295		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
296		    broken && sym->st_shndx == SHN_UNDEF) {
297			/*
298			 * XXX DANGER WILL ROBINSON!
299			 * You might think this is stupid, as it intentionally
300			 * defeats lazy binding -- and you'd be right.
301			 * Unfortunately, for lazy binding to work right, we
302			 * need to a way to force the GOT slots used for
303			 * function pointers to be resolved immediately.  This
304			 * is supposed to be done automatically by the linker,
305			 * by not outputting a PLT slot and setting st_value
306			 * to 0 if there are non-PLT references, but older
307			 * versions of GNU ld do not do this.
308			 */
309			def = find_symdef(i, obj, &defobj, false, NULL);
310			if (def == NULL)
311				return -1;
312			*got = def->st_value + (Elf_Addr)defobj->relocbase;
313		} else
314#endif
315		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
316		    sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
317			/*
318			 * If there are non-PLT references to the function,
319			 * st_value should be 0, forcing us to resolve the
320			 * address immediately.
321			 *
322			 * XXX DANGER WILL ROBINSON!
323			 * The linker is not outputting PLT slots for calls to
324			 * functions that are defined in the same shared
325			 * library.  This is a bug, because it can screw up
326			 * link ordering rules if the symbol is defined in
327			 * more than one module.  For now, if there is a
328			 * definition, we fail the test above and force a full
329			 * symbol lookup.  This means that all intra-module
330			 * calls are bound immediately.  - mycroft, 2003/09/24
331			 */
332			*got = sym->st_value + (Elf_Addr)obj->relocbase;
333			if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
334				dbg("Warning2, i:%d maps to relocbase address:%x",
335				    i, (uint32_t)obj->relocbase);
336			}
337
338		} else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
339			/* Symbols with index SHN_ABS are not relocated. */
340			if (sym->st_shndx != SHN_ABS) {
341				*got = sym->st_value +
342				    (Elf_Addr)obj->relocbase;
343				if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
344					dbg("Warning3, i:%d maps to relocbase address:%x",
345					    i, (uint32_t)obj->relocbase);
346				}
347			}
348		} else {
349			/* TODO: add cache here */
350			def = find_symdef(i, obj, &defobj, false, NULL);
351			if (def == NULL) {
352				dbg("Warning4, cant find symbole %d", i);
353				return -1;
354			}
355			*got = def->st_value + (Elf_Addr)defobj->relocbase;
356			if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) {
357				dbg("Warning4, i:%d maps to relocbase address:%x",
358				    i, (uint32_t)obj->relocbase);
359				dbg("via first obj symbol %s",
360				    obj->strtab + obj->symtab[i].st_name);
361				dbg("found in obj %p:%s",
362				    defobj, defobj->path);
363			}
364		}
365
366		dbg("  --> now %lx", (u_long) *got);
367		++sym;
368		++got;
369	}
370
371	got = obj->pltgot;
372	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
373	for (rel = obj->rel; rel < rellim; rel++) {
374		Elf_Word	r_symndx, r_type;
375		void		*where;
376
377		where = obj->relocbase + rel->r_offset;
378		r_symndx = ELF_R_SYM(rel->r_info);
379		r_type = ELF_R_TYPE(rel->r_info);
380
381		switch (r_type & 0xff) {
382		case R_TYPE(NONE):
383			break;
384
385		case R_TYPE(REL32): {
386			/* 32-bit PC-relative reference */
387			const size_t rlen =
388			    ELF_R_NXTTYPE_64_P(r_type)
389				? sizeof(Elf_Sxword)
390				: sizeof(Elf_Sword);
391			Elf_Sxword old = load_ptr(where, rlen);
392			Elf_Sxword val = old;
393
394			def = obj->symtab + r_symndx;
395
396			if (r_symndx >= obj->gotsym) {
397				val += got[obj->local_gotno + r_symndx - obj->gotsym];
398				dbg("REL32/G(%p) %p --> %p (%s) in %s",
399				    where, (void *)old, (void *)val,
400				    obj->strtab + def->st_name,
401				    obj->path);
402			} else {
403				/*
404				 * XXX: ABI DIFFERENCE!
405				 *
406				 * Old NetBSD binutils would generate shared
407				 * libs with section-relative relocations being
408				 * already adjusted for the start address of
409				 * the section.
410				 *
411				 * New binutils, OTOH, generate shared libs
412				 * with the same relocations being based at
413				 * zero, so we need to add in the start address
414				 * of the section.
415				 *
416				 * --rkb, Oct 6, 2001
417				 */
418
419				if (def->st_info ==
420				    ELF_ST_INFO(STB_LOCAL, STT_SECTION)
421#ifdef SUPPORT_OLD_BROKEN_LD
422				    && !broken
423#endif
424				    )
425					val += (Elf_Addr)def->st_value;
426
427				val += (Elf_Addr)obj->relocbase;
428
429				dbg("REL32/L(%p) %p -> %p (%s) in %s",
430				    where, (void *)old, (void *)val,
431				    obj->strtab + def->st_name, obj->path);
432			}
433			store_ptr(where, val, rlen);
434			break;
435		}
436
437		default:
438			dbg("sym = %lu, type = %lu, offset = %p, "
439			    "contents = %p, symbol = %s",
440			    (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
441			    (void *)rel->r_offset,
442			    (void *)load_ptr(where, sizeof(Elf_Sword)),
443			    obj->strtab + obj->symtab[r_symndx].st_name);
444			_rtld_error("%s: Unsupported relocation type %ld "
445			    "in non-PLT relocations",
446			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
447			return -1;
448		}
449	}
450
451	return 0;
452}
453
454/*
455 *  Process the PLT relocations.
456 */
457int
458reloc_plt(Obj_Entry *obj)
459{
460#if 0
461	const Elf_Rel *rellim;
462	const Elf_Rel *rel;
463
464	dbg("reloc_plt obj:%p pltrel:%p sz:%d", obj, obj->pltrel, (int)obj->pltrelsize);
465	dbg("gottable %p num syms:%d", obj->pltgot, obj->symtabno );
466	dbg("*****************************************************");
467	rellim = (const Elf_Rel *)((char *)obj->pltrel +
468	    obj->pltrelsize);
469	for (rel = obj->pltrel;  rel < rellim;  rel++) {
470		Elf_Addr *where;
471		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
472		*where += (Elf_Addr )obj->relocbase;
473	}
474
475#endif
476	/* PLT fixups were done above in the GOT relocation. */
477	return (0);
478}
479
480/*
481 * LD_BIND_NOW was set - force relocation for all jump slots
482 */
483int
484reloc_jmpslots(Obj_Entry *obj)
485{
486	/* Do nothing */
487	obj->jmpslots_done = true;
488
489	return (0);
490}
491
492Elf_Addr
493reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
494    		const Obj_Entry *obj, const Elf_Rel *rel)
495{
496
497	/* Do nothing */
498
499	return target;
500}
501
502void
503allocate_initial_tls(Obj_Entry *objs)
504{
505
506}
507
508void *
509__tls_get_addr(tls_index* ti)
510{
511	return (NULL);
512}
513