rmreloc.c revision 1.1.6.2 1 /* $NetBSD: rmreloc.c,v 1.1.6.2 2006/04/19 02:31:57 elad Exp $ */
2
3 /*
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root (at) ihack.net>
7 * All rights reserved.
8 *
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.
22 *
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.
33 */
34 /*
35 * rmreloc.c - relocate an ELFish RISC OS relocatable module.
36 */
37 /*
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
41 *
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.
48 */
49
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>
55
56 #include <riscoscalls.h>
57
58 os_error *relocate_self(Elf_Dyn *, caddr_t, caddr_t);
59
60 #define assert(x) /* nothing */
61
62 /*
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.
66 */
67
68 typedef struct {
69 caddr_t 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;
74
75 #define rdbg(x) /* nothing */
76
77 /*
78 * It is possible for the compiler to emit relocations for unaligned data.
79 * We handle this situation with these inlines.
80 */
81 #define RELOC_ALIGNED_P(x) \
82 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
83
84 static inline Elf_Addr
85 load_ptr(void *where)
86 {
87 Elf_Addr res;
88
89 memcpy(&res, where, sizeof(res));
90
91 return (res);
92 }
93
94 static inline void
95 store_ptr(void *where, Elf_Addr val)
96 {
97
98 memcpy(where, &val, sizeof(val));
99 }
100
101 static struct os_error bad_reloc = {
102 0, "Unhandled ELF redirection"
103 };
104
105 os_error *
106 relocate_self(Elf_Dyn *dynamic, caddr_t oldbase, caddr_t newbase)
107 {
108 Elf_Dyn *dynp;
109 Obj_Entry o, *obj;
110 const Elf_Rel *rel;
111 Elf_Addr relsz = 0;
112
113 obj = &o; obj->dynamic = dynamic; obj->relocbase = newbase;
114
115 for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
116 switch (dynp->d_tag) {
117 case DT_REL:
118 obj->rel = (const Elf_Rel *)
119 (obj->relocbase + dynp->d_un.d_ptr);
120 break;
121 case DT_RELSZ:
122 relsz = dynp->d_un.d_val;
123 break;
124 case DT_RELENT:
125 assert(dynp->d_un.d_val == sizeof(Elf_Rel));
126 break;
127 }
128 }
129
130 obj->rellim = (const Elf_Rel *)((caddr_t)obj->rel + relsz);
131
132 for (rel = obj->rel; rel < obj->rellim; rel++) {
133 Elf_Addr *where;
134 Elf_Addr tmp;
135
136 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
137
138 switch (ELF_R_TYPE(rel->r_info)) {
139 case R_TYPE(NONE):
140 break;
141
142 case R_TYPE(RELATIVE): /* word32 B + A */
143 if (__predict_true(RELOC_ALIGNED_P(where))) {
144 tmp = *where + (Elf_Addr)obj->relocbase -
145 (Elf_Addr)oldbase;
146 *where = tmp;
147 } else {
148 tmp = load_ptr(where) +
149 (Elf_Addr)obj->relocbase -
150 (Elf_Addr)oldbase;
151 store_ptr(where, tmp);
152 }
153 rdbg(("RELATIVE in %s --> %p", obj->path,
154 (void *)tmp));
155 break;
156
157 default:
158 return &bad_reloc;
159 }
160 }
161 return NULL;
162 }
163