xref: /netbsd-src/sys/arch/acorn32/stand/lib/rmreloc.c (revision 53524e44efd7c7176da8dc8190a698b2fe184db1)
1*53524e44Schristos /* $NetBSD: rmreloc.c,v 1.3 2007/03/04 05:59:07 christos Exp $ */
24123cff8Sbjh21 
34123cff8Sbjh21 /*
44123cff8Sbjh21  * Copyright 1996 John D. Polstra.
54123cff8Sbjh21  * Copyright 1996 Matt Thomas <matt@3am-software.com>
64123cff8Sbjh21  * Copyright 2002 Charles M. Hannum <root@ihack.net>
74123cff8Sbjh21  * All rights reserved.
84123cff8Sbjh21  *
94123cff8Sbjh21  * Redistribution and use in source and binary forms, with or without
104123cff8Sbjh21  * modification, are permitted provided that the following conditions
114123cff8Sbjh21  * are met:
124123cff8Sbjh21  * 1. Redistributions of source code must retain the above copyright
134123cff8Sbjh21  *    notice, this list of conditions and the following disclaimer.
144123cff8Sbjh21  * 2. Redistributions in binary form must reproduce the above copyright
154123cff8Sbjh21  *    notice, this list of conditions and the following disclaimer in the
164123cff8Sbjh21  *    documentation and/or other materials provided with the distribution.
174123cff8Sbjh21  * 3. All advertising materials mentioning features or use of this software
184123cff8Sbjh21  *    must display the following acknowledgement:
194123cff8Sbjh21  *      This product includes software developed by John Polstra.
204123cff8Sbjh21  * 4. The name of the author may not be used to endorse or promote products
214123cff8Sbjh21  *    derived from this software without specific prior written permission.
224123cff8Sbjh21  *
234123cff8Sbjh21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
244123cff8Sbjh21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
254123cff8Sbjh21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
264123cff8Sbjh21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
274123cff8Sbjh21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
284123cff8Sbjh21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
294123cff8Sbjh21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
304123cff8Sbjh21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
314123cff8Sbjh21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
324123cff8Sbjh21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
334123cff8Sbjh21  */
344123cff8Sbjh21 /*
354123cff8Sbjh21  * rmreloc.c - relocate an ELFish RISC OS relocatable module.
364123cff8Sbjh21  */
374123cff8Sbjh21 /*
384123cff8Sbjh21  * This code is a heavily hacked version of parts of:
394123cff8Sbjh21  * lib/libexec/ld.elf_so/headers.c
404123cff8Sbjh21  * lib/libexec/ld.elf_so/arch/arm/mdreloc.c
414123cff8Sbjh21  *
424123cff8Sbjh21  * At present it only deals with DT_REL tables containing R_ARM_NONE
434123cff8Sbjh21  * and R_ARM_RELATIVE relocations, because those are all that my
444123cff8Sbjh21  * linker emits.  More can be added as needed.  Note that this has to
454123cff8Sbjh21  * handle relocating already-relocated code, e.g. after *RMTidy, so
464123cff8Sbjh21  * most relocations have to reference oldbase, which ld.elf_so just
474123cff8Sbjh21  * assumes is zero.  There may be a cleverer way to do this.
484123cff8Sbjh21  */
494123cff8Sbjh21 
504123cff8Sbjh21 #include <sys/types.h>
514123cff8Sbjh21 #include <sys/stdint.h>
524123cff8Sbjh21 #include <lib/libsa/stand.h>
534123cff8Sbjh21 #define ELFSIZE 32
544123cff8Sbjh21 #include <sys/exec_elf.h>
554123cff8Sbjh21 
564123cff8Sbjh21 #include <riscoscalls.h>
574123cff8Sbjh21 
58*53524e44Schristos os_error *relocate_self(Elf_Dyn *, void *, void *);
594123cff8Sbjh21 
604123cff8Sbjh21 #define assert(x) /* nothing */
614123cff8Sbjh21 
624123cff8Sbjh21 /*
634123cff8Sbjh21  * While relocating ourselves, we must not refer to any global variables.
644123cff8Sbjh21  * This includes _DYNAMIC -- the startup code finds it for us and passes
654123cff8Sbjh21  * it to us along with the base address of the module.
664123cff8Sbjh21  */
674123cff8Sbjh21 
684123cff8Sbjh21 typedef struct {
69*53524e44Schristos 	void *        relocbase;	/* Reloc const = mapbase - *vaddrbase */
704123cff8Sbjh21 	Elf_Dyn        *dynamic;	/* Dynamic section */
714123cff8Sbjh21 	const Elf_Rel  *rel;		/* Relocation entries */
724123cff8Sbjh21 	const Elf_Rel  *rellim;		/* Limit of Relocation entries */
734123cff8Sbjh21 } Obj_Entry;
744123cff8Sbjh21 
754123cff8Sbjh21 #define rdbg(x) /* nothing */
764123cff8Sbjh21 
774123cff8Sbjh21 /*
784123cff8Sbjh21  * It is possible for the compiler to emit relocations for unaligned data.
794123cff8Sbjh21  * We handle this situation with these inlines.
804123cff8Sbjh21  */
814123cff8Sbjh21 #define	RELOC_ALIGNED_P(x) \
824123cff8Sbjh21 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
834123cff8Sbjh21 
844123cff8Sbjh21 static inline Elf_Addr
load_ptr(void * where)854123cff8Sbjh21 load_ptr(void *where)
864123cff8Sbjh21 {
874123cff8Sbjh21 	Elf_Addr res;
884123cff8Sbjh21 
894123cff8Sbjh21 	memcpy(&res, where, sizeof(res));
904123cff8Sbjh21 
914123cff8Sbjh21 	return (res);
924123cff8Sbjh21 }
934123cff8Sbjh21 
944123cff8Sbjh21 static inline void
store_ptr(void * where,Elf_Addr val)954123cff8Sbjh21 store_ptr(void *where, Elf_Addr val)
964123cff8Sbjh21 {
974123cff8Sbjh21 
984123cff8Sbjh21 	memcpy(where, &val, sizeof(val));
994123cff8Sbjh21 }
1004123cff8Sbjh21 
1014123cff8Sbjh21 static struct os_error bad_reloc = {
1024123cff8Sbjh21 	0, "Unhandled ELF redirection"
1034123cff8Sbjh21 };
1044123cff8Sbjh21 
1054123cff8Sbjh21 os_error *
relocate_self(Elf_Dyn * dynamic,void * oldbase,void * newbase)106*53524e44Schristos relocate_self(Elf_Dyn *dynamic, void *oldbase, void *newbase)
1074123cff8Sbjh21 {
1084123cff8Sbjh21 	Elf_Dyn *dynp;
10929c1a4c2Schristos 	Obj_Entry o = { 0 };
11029c1a4c2Schristos 	Obj_Entry *obj;
1114123cff8Sbjh21 	const Elf_Rel *rel;
1124123cff8Sbjh21 	Elf_Addr        relsz = 0;
1134123cff8Sbjh21 
1144123cff8Sbjh21 	obj = &o; obj->dynamic = dynamic; obj->relocbase = newbase;
1154123cff8Sbjh21 
1164123cff8Sbjh21 	for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
1174123cff8Sbjh21 		switch (dynp->d_tag) {
1184123cff8Sbjh21 		case DT_REL:
1194123cff8Sbjh21 			obj->rel = (const Elf_Rel *)
1204123cff8Sbjh21 			    (obj->relocbase + dynp->d_un.d_ptr);
1214123cff8Sbjh21 			break;
1224123cff8Sbjh21 		case DT_RELSZ:
1234123cff8Sbjh21 			relsz = dynp->d_un.d_val;
1244123cff8Sbjh21 			break;
1254123cff8Sbjh21 		case DT_RELENT:
1264123cff8Sbjh21 			assert(dynp->d_un.d_val == sizeof(Elf_Rel));
1274123cff8Sbjh21 			break;
1284123cff8Sbjh21 		}
1294123cff8Sbjh21 	}
1304123cff8Sbjh21 
131*53524e44Schristos 	obj->rellim = (const Elf_Rel *)((void *)obj->rel + relsz);
1324123cff8Sbjh21 
1334123cff8Sbjh21 	for (rel = obj->rel; rel < obj->rellim; rel++) {
1344123cff8Sbjh21 		Elf_Addr        *where;
1354123cff8Sbjh21 		Elf_Addr         tmp;
1364123cff8Sbjh21 
1374123cff8Sbjh21 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
1384123cff8Sbjh21 
1394123cff8Sbjh21 		switch (ELF_R_TYPE(rel->r_info)) {
1404123cff8Sbjh21 		case R_TYPE(NONE):
1414123cff8Sbjh21 			break;
1424123cff8Sbjh21 
1434123cff8Sbjh21 		case R_TYPE(RELATIVE):	/* word32 B + A */
1444123cff8Sbjh21 			if (__predict_true(RELOC_ALIGNED_P(where))) {
1454123cff8Sbjh21 				tmp = *where + (Elf_Addr)obj->relocbase -
1464123cff8Sbjh21 				    (Elf_Addr)oldbase;
1474123cff8Sbjh21 				*where = tmp;
1484123cff8Sbjh21 			} else {
1494123cff8Sbjh21 				tmp = load_ptr(where) +
1504123cff8Sbjh21 				    (Elf_Addr)obj->relocbase -
1514123cff8Sbjh21 				    (Elf_Addr)oldbase;
1524123cff8Sbjh21 				store_ptr(where, tmp);
1534123cff8Sbjh21 			}
1544123cff8Sbjh21 			rdbg(("RELATIVE in %s --> %p", obj->path,
1554123cff8Sbjh21 			    (void *)tmp));
1564123cff8Sbjh21 			break;
1574123cff8Sbjh21 
1584123cff8Sbjh21 		default:
1594123cff8Sbjh21 			return &bad_reloc;
1604123cff8Sbjh21 		}
1614123cff8Sbjh21 	}
1624123cff8Sbjh21 	return NULL;
1634123cff8Sbjh21 }
164