Home | History | Annotate | Line # | Download | only in mips
mips_reloc.c revision 1.17
      1 /*	$NetBSD: mips_reloc.c,v 1.17 2002/09/12 17:08:32 mycroft Exp $	*/
      2 
      3 /*
      4  * Copyright 1997 Michael L. Hitch <mhitch (at) montana.edu>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 
     31 #include <stdarg.h>
     32 #include <sys/types.h>
     33 #include <sys/stat.h>
     34 
     35 #include "debug.h"
     36 #include "rtld.h"
     37 
     38 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
     39 caddr_t _rtld_bind_mips(Elf_Word, Elf_Addr, Elf_Addr, Elf_Addr);
     40 
     41 caddr_t
     42 _rtld_bind_mips(a0, a1, a2, a3)
     43 	Elf_Word a0;
     44 	Elf_Addr a1, a2, a3;
     45 {
     46 	Elf_Addr *u = (Elf_Addr *)(a2 - 0x7ff0);
     47 	const Obj_Entry *obj = (Obj_Entry *)(u[1] & 0x7fffffff);
     48 	const Elf_Sym *def;
     49 	const Obj_Entry *defobj;
     50 
     51 	def = _rtld_find_symdef(a0, obj, &defobj, true);
     52 	if (def) {
     53 		u[obj->local_gotno + a0 - obj->gotsym] = (Elf_Addr)
     54 		    (def->st_value + defobj->relocbase);
     55 		return((caddr_t)(def->st_value + defobj->relocbase));
     56 	}
     57 
     58 	return(NULL);	/* XXX */
     59 }
     60 
     61 void
     62 _rtld_setup_pltgot(obj)
     63 	const Obj_Entry *obj;
     64 {
     65 	Elf_Addr *got = obj->pltgot;
     66 	const Elf_Sym *sym = obj->symtab;
     67 	const Elf_Sym *def;
     68 	const Obj_Entry *defobj;
     69 	int i;
     70 
     71 	i = (got[1] & 0x80000000) ? 2 : 1;
     72 	/* Relocate the local GOT entries */
     73 	while (i < obj->local_gotno)
     74 		got[i++] += (Elf_Word)obj->relocbase;
     75 	got += obj->local_gotno;
     76 	sym += obj->gotsym;
     77 	/* Now do the global GOT entries */
     78 	for (i = obj->gotsym; i < obj->symtabno; i++) {
     79 		rdbg(1, (" doing got %d sym %p (%s, %x)", i - obj->gotsym,
     80 		    sym, sym->st_name + obj->strtab, *got));
     81 
     82 		def = _rtld_find_symdef(i, obj, &defobj, true);
     83 		if (def == NULL)
     84 			_rtld_error(
     85 	    "%s: Undefined PLT symbol \"%s\" (section type = %ld, symnum = %ld)",
     86 			    obj->path, sym->st_name + obj->strtab,
     87 			    (u_long) ELF_ST_TYPE(sym->st_info), (u_long) i);
     88 		else {
     89 			if (sym->st_shndx == SHN_UNDEF) {
     90 #if 0	/* These don't seem to work? */
     91 
     92 				if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) {
     93 					if (sym->st_value)
     94 						*got = sym->st_value +
     95 						    (Elf_Word)obj->relocbase;
     96 					else
     97 						*got = def->st_value +
     98 						    (Elf_Word)defobj->relocbase;
     99 				} else
    100 #endif
    101 					*got = def->st_value +
    102 					    (Elf_Word)defobj->relocbase;
    103 			} else if (sym->st_shndx == SHN_COMMON) {
    104 				*got = def->st_value +
    105 				    (Elf_Word)defobj->relocbase;
    106 			} else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
    107 			    *got != sym->st_value) {
    108 				*got += (Elf_Word)obj->relocbase;
    109 			} else if (ELF_ST_TYPE(sym->st_info) == STT_SECTION &&
    110 			    ELF_ST_BIND(sym->st_info) == STB_GLOBAL) {
    111 				if (sym->st_shndx == SHN_ABS)
    112 					*got = sym->st_value +
    113 					    (Elf_Word)obj->relocbase;
    114 				/* else SGI stuff ignored */
    115 			} else
    116 				*got = def->st_value +
    117 				    (Elf_Word)defobj->relocbase;
    118 		}
    119 
    120 		++sym;
    121 		++got;
    122 	}
    123 
    124 	obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
    125 	/* XXX only if obj->pltgot[1] & 0x80000000 ?? */
    126 	obj->pltgot[1] |= (Elf_Addr) obj;
    127 }
    128 
    129 void
    130 _rtld_relocate_nonplt_self(dynp, relocbase)
    131 	Elf_Dyn *dynp;
    132 	Elf_Addr relocbase;
    133 {
    134 	const Elf_Rel *rel = 0, *rellim;
    135 	Elf_Addr relsz = 0;
    136 	Elf_Addr *where;
    137 	const Elf_Sym *def, *symtab;
    138 
    139 	for (; dynp->d_tag != DT_NULL; dynp++) {
    140 		switch (dynp->d_tag) {
    141 		case DT_REL:
    142 			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
    143 			break;
    144 		case DT_RELSZ:
    145 			relsz = dynp->d_un.d_val;
    146 			break;
    147 		case DT_SYMTAB:
    148 			symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
    149 			break;
    150 		}
    151 	}
    152 	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
    153 	for (; rel < rellim; rel++) {
    154 		where = (Elf_Addr *)(relocbase + rel->r_offset);
    155 
    156 		switch (ELF_R_TYPE(rel->r_info)) {
    157 		case R_TYPE(NONE):
    158 			break;
    159 
    160 		case R_TYPE(REL32):
    161 			def = symtab + ELF_R_SYM(rel->r_info);
    162 			if (ELF_ST_BIND(def->st_info) == STB_LOCAL &&
    163 			    ELF_ST_TYPE(def->st_info) == STT_SECTION) {
    164 				*where += (Elf_Addr)def->st_value;
    165 				*where += (Elf_Addr)relocbase;
    166 			} else
    167 				abort();
    168 			break;
    169 
    170 		default:
    171 			abort();
    172 		}
    173 	}
    174 }
    175 
    176 int
    177 _rtld_relocate_nonplt_objects(obj, self, dodebug)
    178 	const Obj_Entry *obj;
    179 	bool self;
    180 	bool dodebug;
    181 {
    182 	const Elf_Rel *rel;
    183 
    184 	if (self)
    185 		return 0;
    186 
    187 	for (rel = obj->rel; rel < obj->rellim; rel++) {
    188 		Elf_Addr        *where;
    189 		const Elf_Sym   *def;
    190 		const Obj_Entry *defobj;
    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_TYPE(NONE):
    198 			break;
    199 
    200 		case R_TYPE(REL32):
    201 			/* 32-bit PC-relative reference */
    202 			def = obj->symtab + symnum;
    203 
    204 			if (ELF_ST_BIND(def->st_info) == STB_LOCAL &&
    205 			  (ELF_ST_TYPE(def->st_info) == STT_SECTION ||
    206 			   ELF_ST_TYPE(def->st_info) == STT_NOTYPE)) {
    207 				/*
    208 				 * XXX: ABI DIFFERENCE!
    209 				 *
    210 				 * Old NetBSD binutils would generate shared
    211 				 * libs with section-relative relocations being
    212 				 * already adjusted for the start address of
    213 				 * the section.
    214 				 *
    215 				 * New binutils, OTOH, generate shared libs
    216 				 * with the same relocations being based at
    217 				 * zero, so we need to add in the start address
    218 				 * of the section.
    219 				 *
    220 				 * We assume that all section-relative relocs
    221 				 * with contents less than the start of the
    222 				 * section need to be adjusted; this should
    223 				 * work with both old and new shlibs.
    224 				 *
    225 				 * --rkb, Oct 6, 2001
    226 				 */
    227 				if (def->st_info == STT_SECTION &&
    228 				    *where < def->st_value)
    229 					*where += (Elf_Addr)def->st_value;
    230 
    231 				*where += (Elf_Addr)obj->relocbase;
    232 
    233 				rdbg(dodebug, ("REL32 %s in %s --> %p in %s",
    234 				    obj->strtab + def->st_name, obj->path,
    235 				    (void *)*where, obj->path));
    236 			} else {
    237 				/* XXX maybe do something re: bootstrapping? */
    238 				def = _rtld_find_symdef(symnum, obj, &defobj,
    239 				    false);
    240 				if (def == NULL)
    241 					return -1;
    242 				*where += (Elf_Addr)(defobj->relocbase +
    243 				    def->st_value);
    244 				rdbg(dodebug, ("REL32 %s in %s --> %p in %s",
    245 				    obj->strtab + obj->symtab[symnum].st_name,
    246 				    obj->path, (void *)*where, defobj->path));
    247 			}
    248 			break;
    249 
    250 		default:
    251 			rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
    252 			    "contents = %p, symbol = %s",
    253 			    symnum, (u_long)ELF_R_TYPE(rel->r_info),
    254 			    (void *)rel->r_offset, (void *)*where,
    255 			    obj->strtab + obj->symtab[symnum].st_name));
    256 			_rtld_error("%s: Unsupported relocation type %ld "
    257 			    "in non-PLT relocations\n",
    258 			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
    259 			return -1;
    260 		}
    261 	}
    262 	return 0;
    263 }
    264 
    265 int
    266 _rtld_relocate_plt_lazy(obj, dodebug)
    267 	const Obj_Entry *obj;
    268 	bool dodebug;
    269 {
    270 	const Elf_Rel *rel;
    271 
    272 	if (!obj->isdynamic)
    273 		return 0;
    274 
    275 	for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
    276 		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
    277 
    278 		/* Just relocate the GOT slots pointing into the PLT */
    279 		*where += (Elf_Addr)obj->relocbase;
    280 		rdbg(dodebug, ("fixup !main in %s --> %p", obj->path,
    281 		    (void *)*where));
    282 	}
    283 
    284 	return 0;
    285 }
    286 
    287 int
    288 _rtld_relocate_plt_object(obj, rela, addrp, dodebug)
    289 	const Obj_Entry *obj;
    290 	const Elf_Rela *rela;
    291 	caddr_t *addrp;
    292 	bool dodebug;
    293 {
    294 	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
    295 	Elf_Addr new_value;
    296 
    297 	/* Fully resolve procedure addresses now */
    298 
    299 	if (obj->isdynamic) {
    300 		/* Just relocate the GOT slots pointing into the PLT */
    301 		new_value = *where + (Elf_Addr)(obj->relocbase);
    302 		rdbg(dodebug, ("fixup !main in %s --> %p", obj->path,
    303 		    (void *)*where));
    304 	} else {
    305 		return 0;
    306 	}
    307 	if (*where != new_value)
    308 		*where = new_value;
    309 
    310 	*addrp = (caddr_t)new_value;
    311 	return 0;
    312 }
    313