Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / acorn32 / stand / lib / rmreloc.c
blobd7a819772fb4c723ae4bcf6f678f46a368c141bb
1 /* $NetBSD: rmreloc.c,v 1.2 2006/06/25 21:32:41 christos Exp $ */
3 /*
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt@3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root@ihack.net>
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by John Polstra.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * rmreloc.c - relocate an ELFish RISC OS relocatable module.
38 * This code is a heavily hacked version of parts of:
39 * lib/libexec/ld.elf_so/headers.c
40 * lib/libexec/ld.elf_so/arch/arm/mdreloc.c
42 * At present it only deals with DT_REL tables containing R_ARM_NONE
43 * and R_ARM_RELATIVE relocations, because those are all that my
44 * linker emits. More can be added as needed. Note that this has to
45 * handle relocating already-relocated code, e.g. after *RMTidy, so
46 * most relocations have to reference oldbase, which ld.elf_so just
47 * assumes is zero. There may be a cleverer way to do this.
50 #include <sys/types.h>
51 #include <sys/stdint.h>
52 #include <lib/libsa/stand.h>
53 #define ELFSIZE 32
54 #include <sys/exec_elf.h>
56 #include <riscoscalls.h>
58 os_error *relocate_self(Elf_Dyn *, void *, void *);
60 #define assert(x) /* nothing */
63 * While relocating ourselves, we must not refer to any global variables.
64 * This includes _DYNAMIC -- the startup code finds it for us and passes
65 * it to us along with the base address of the module.
68 typedef struct {
69 void * relocbase; /* Reloc const = mapbase - *vaddrbase */
70 Elf_Dyn *dynamic; /* Dynamic section */
71 const Elf_Rel *rel; /* Relocation entries */
72 const Elf_Rel *rellim; /* Limit of Relocation entries */
73 } Obj_Entry;
75 #define rdbg(x) /* nothing */
78 * It is possible for the compiler to emit relocations for unaligned data.
79 * We handle this situation with these inlines.
81 #define RELOC_ALIGNED_P(x) \
82 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
84 static inline Elf_Addr
85 load_ptr(void *where)
87 Elf_Addr res;
89 memcpy(&res, where, sizeof(res));
91 return (res);
94 static inline void
95 store_ptr(void *where, Elf_Addr val)
98 memcpy(where, &val, sizeof(val));
101 static struct os_error bad_reloc = {
102 0, "Unhandled ELF redirection"
105 os_error *
106 relocate_self(Elf_Dyn *dynamic, void *oldbase, void *newbase)
108 Elf_Dyn *dynp;
109 Obj_Entry o = { 0 };
110 Obj_Entry *obj;
111 const Elf_Rel *rel;
112 Elf_Addr relsz = 0;
114 obj = &o; obj->dynamic = dynamic; obj->relocbase = newbase;
116 for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
117 switch (dynp->d_tag) {
118 case DT_REL:
119 obj->rel = (const Elf_Rel *)
120 (obj->relocbase + dynp->d_un.d_ptr);
121 break;
122 case DT_RELSZ:
123 relsz = dynp->d_un.d_val;
124 break;
125 case DT_RELENT:
126 assert(dynp->d_un.d_val == sizeof(Elf_Rel));
127 break;
131 obj->rellim = (const Elf_Rel *)((void *)obj->rel + relsz);
133 for (rel = obj->rel; rel < obj->rellim; rel++) {
134 Elf_Addr *where;
135 Elf_Addr tmp;
137 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
139 switch (ELF_R_TYPE(rel->r_info)) {
140 case R_TYPE(NONE):
141 break;
143 case R_TYPE(RELATIVE): /* word32 B + A */
144 if (__predict_true(RELOC_ALIGNED_P(where))) {
145 tmp = *where + (Elf_Addr)obj->relocbase -
146 (Elf_Addr)oldbase;
147 *where = tmp;
148 } else {
149 tmp = load_ptr(where) +
150 (Elf_Addr)obj->relocbase -
151 (Elf_Addr)oldbase;
152 store_ptr(where, tmp);
154 rdbg(("RELATIVE in %s --> %p", obj->path,
155 (void *)tmp));
156 break;
158 default:
159 return &bad_reloc;
162 return NULL;