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