1 /*
2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 *
5 *
6 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
9
10 #ifdef _BOOT_MODE
11 #include <boot/arch.h>
12 #endif
13
14 #include <KernelExport.h>
15
16 #include <elf_priv.h>
17 #include <arch/elf.h>
18
19
20 #define CHATTY 0
21
22 #ifdef _BOOT_MODE
23 status_t
boot_arch_elf_relocate_rel(struct preloaded_elf32_image * image,Elf32_Rel * rel,int rel_len)24 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
25 int rel_len)
26 #else
27 int
28 arch_elf_relocate_rel(struct elf_image_info *image,
29 struct elf_image_info *resolve_image, Elf32_Rel *rel, int rel_len)
30 #endif
31 {
32 // there are no rel entries in PPC elf
33 return B_NO_ERROR;
34 }
35
36
37 static inline void
write_word32(addr_t P,Elf32_Word value)38 write_word32(addr_t P, Elf32_Word value)
39 {
40 *(Elf32_Word*)P = value;
41 }
42
43
44 static inline void
write_word30(addr_t P,Elf32_Word value)45 write_word30(addr_t P, Elf32_Word value)
46 {
47 // bits 0:29
48 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0x3) | (value << 2);
49 }
50
51
52 static inline bool
write_low24_check(addr_t P,Elf32_Word value)53 write_low24_check(addr_t P, Elf32_Word value)
54 {
55 // bits 6:29
56 if ((value & 0x3f000000) && (~value & 0x3f800000))
57 return false;
58 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0xfc000003)
59 | ((value & 0x00ffffff) << 2);
60 return true;
61 }
62
63
64 static inline bool
write_low14_check(addr_t P,Elf32_Word value)65 write_low14_check(addr_t P, Elf32_Word value)
66 {
67 // bits 16:29
68 if ((value & 0x3fffc000) && (~value & 0x3fffe000))
69 return false;
70 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0xffff0003)
71 | ((value & 0x00003fff) << 2);
72 return true;
73 }
74
75
76 static inline void
write_half16(addr_t P,Elf32_Word value)77 write_half16(addr_t P, Elf32_Word value)
78 {
79 // bits 16:29
80 *(Elf32_Half*)P = (Elf32_Half)value;
81 }
82
83
84 static inline bool
write_half16_check(addr_t P,Elf32_Word value)85 write_half16_check(addr_t P, Elf32_Word value)
86 {
87 // bits 16:29
88 if ((value & 0xffff0000) && (~value & 0xffff8000))
89 return false;
90 *(Elf32_Half*)P = (Elf32_Half)value;
91 return true;
92 }
93
94
95 static inline Elf32_Word
lo(Elf32_Word value)96 lo(Elf32_Word value)
97 {
98 return (value & 0xffff);
99 }
100
101
102 static inline Elf32_Word
hi(Elf32_Word value)103 hi(Elf32_Word value)
104 {
105 return ((value >> 16) & 0xffff);
106 }
107
108
109 static inline Elf32_Word
ha(Elf32_Word value)110 ha(Elf32_Word value)
111 {
112 return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff);
113 }
114
115
116 #ifdef _BOOT_MODE
117 status_t
boot_arch_elf_relocate_rela(struct preloaded_elf32_image * image,Elf32_Rela * rel,int rel_len)118 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
119 Elf32_Rela *rel, int rel_len)
120 #else
121 int
122 arch_elf_relocate_rela(struct elf_image_info *image,
123 struct elf_image_info *resolve_image, Elf32_Rela *rel, int rel_len)
124 #endif
125 {
126 int i;
127 Elf32_Sym *sym;
128 int vlErr;
129
130 Elf32_Addr S = 0; // symbol address
131 addr_t R = 0; // section relative symbol address
132
133 addr_t G = 0; // GOT address
134 addr_t L = 0; // PLT address
135
136 #define P ((addr_t)(image->text_region.delta + rel[i].r_offset))
137 #define A ((addr_t)rel[i].r_addend)
138 #define B (image->text_region.delta)
139
140 // TODO: Get the GOT address!
141 #define REQUIRE_GOT \
142 if (G == 0) { \
143 dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
144 return B_ERROR; \
145 }
146
147 // TODO: Get the PLT address!
148 #define REQUIRE_PLT \
149 if (L == 0) { \
150 dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
151 return B_ERROR; \
152 }
153
154 for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) {
155 #if CHATTY
156 dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
157 ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
158 #endif
159 switch (ELF32_R_TYPE(rel[i].r_info)) {
160 case R_PPC_SECTOFF:
161 case R_PPC_SECTOFF_LO:
162 case R_PPC_SECTOFF_HI:
163 case R_PPC_SECTOFF_HA:
164 dprintf("arch_elf_relocate_rela(): Getting section relative "
165 "symbol addresses not yet supported!\n");
166 return B_ERROR;
167
168 case R_PPC_ADDR32:
169 case R_PPC_ADDR24:
170 case R_PPC_ADDR16:
171 case R_PPC_ADDR16_LO:
172 case R_PPC_ADDR16_HI:
173 case R_PPC_ADDR16_HA:
174 case R_PPC_ADDR14:
175 case R_PPC_ADDR14_BRTAKEN:
176 case R_PPC_ADDR14_BRNTAKEN:
177 case R_PPC_REL24:
178 case R_PPC_REL14:
179 case R_PPC_REL14_BRTAKEN:
180 case R_PPC_REL14_BRNTAKEN:
181 case R_PPC_GLOB_DAT:
182 case R_PPC_UADDR32:
183 case R_PPC_UADDR16:
184 case R_PPC_REL32:
185 case R_PPC_SDAREL16:
186 case R_PPC_ADDR30:
187 case R_PPC_JMP_SLOT:
188 sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
189
190 #ifdef _BOOT_MODE
191 vlErr = boot_elf_resolve_symbol(image, sym, &S);
192 #else
193 vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
194 #endif
195 if (vlErr < 0) {
196 dprintf("%s(): Failed to relocate "
197 "entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
198 "addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info),
199 rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
200 rel[i].r_addend);
201 return vlErr;
202 }
203 break;
204 }
205
206 switch (ELF32_R_TYPE(rel[i].r_info)) {
207 case R_PPC_NONE:
208 break;
209
210 case R_PPC_COPY:
211 // TODO: Implement!
212 dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet "
213 "supported!\n");
214 return B_ERROR;
215
216 case R_PPC_ADDR32:
217 case R_PPC_GLOB_DAT:
218 case R_PPC_UADDR32:
219 write_word32(P, S + A);
220 break;
221
222 case R_PPC_ADDR24:
223 if (write_low24_check(P, (S + A) >> 2))
224 break;
225 dprintf("R_PPC_ADDR24 overflow\n");
226 return B_BAD_DATA;
227
228 case R_PPC_ADDR16:
229 case R_PPC_UADDR16:
230 if (write_half16_check(P, S + A))
231 break;
232 dprintf("R_PPC_ADDR16 overflow\n");
233 return B_BAD_DATA;
234
235 case R_PPC_ADDR16_LO:
236 write_half16(P, lo(S + A));
237 break;
238
239 case R_PPC_ADDR16_HI:
240 write_half16(P, hi(S + A));
241 break;
242
243 case R_PPC_ADDR16_HA:
244 write_half16(P, ha(S + A));
245 break;
246
247 case R_PPC_ADDR14:
248 case R_PPC_ADDR14_BRTAKEN:
249 case R_PPC_ADDR14_BRNTAKEN:
250 if (write_low14_check(P, (S + A) >> 2))
251 break;
252 dprintf("R_PPC_ADDR14 overflow\n");
253 return B_BAD_DATA;
254
255 case R_PPC_REL24:
256 if (write_low24_check(P, (S + A - P) >> 2))
257 break;
258 dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2);
259 return B_BAD_DATA;
260
261 case R_PPC_REL14:
262 case R_PPC_REL14_BRTAKEN:
263 case R_PPC_REL14_BRNTAKEN:
264 if (write_low14_check(P, (S + A - P) >> 2))
265 break;
266 dprintf("R_PPC_REL14 overflow\n");
267 return B_BAD_DATA;
268
269 case R_PPC_GOT16:
270 REQUIRE_GOT;
271 if (write_half16_check(P, G + A))
272 break;
273 dprintf("R_PPC_GOT16 overflow\n");
274 return B_BAD_DATA;
275
276 case R_PPC_GOT16_LO:
277 REQUIRE_GOT;
278 write_half16(P, lo(G + A));
279 break;
280
281 case R_PPC_GOT16_HI:
282 REQUIRE_GOT;
283 write_half16(P, hi(G + A));
284 break;
285
286 case R_PPC_GOT16_HA:
287 REQUIRE_GOT;
288 write_half16(P, ha(G + A));
289 break;
290
291 case R_PPC_JMP_SLOT:
292 {
293 // If the relative offset is small enough, we fabricate a
294 // relative branch instruction ("b <addr>").
295 addr_t jumpOffset = S - P;
296 if ((jumpOffset & 0xfc000000) != 0
297 && (~jumpOffset & 0xfe000000) != 0) {
298 // Offset > 24 bit.
299 // TODO: Implement!
300 // See System V PPC ABI supplement, p. 5-6!
301 dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: "
302 "Offsets > 24 bit currently not supported!\n");
303 dprintf("jumpOffset: %p\n", (void*)jumpOffset);
304 return B_ERROR;
305 } else {
306 // Offset <= 24 bit
307 // 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK
308 // "b" instruction: opcode = 18, AA = 0, LK = 0
309 // address: 24 high-order bits of 26 bit offset
310 *(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc);
311 }
312 break;
313 }
314
315 case R_PPC_RELATIVE:
316 write_word32(P, B + A);
317 break;
318
319 case R_PPC_LOCAL24PC:
320 // TODO: Implement!
321 // low24*
322 // if (write_low24_check(P, ?)
323 // break;
324 // return B_BAD_DATA;
325 dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet "
326 "supported!\n");
327 return B_ERROR;
328
329 case R_PPC_REL32:
330 write_word32(P, S + A - P);
331 break;
332
333 case R_PPC_PLTREL24:
334 REQUIRE_PLT;
335 if (write_low24_check(P, (L + A - P) >> 2))
336 break;
337 dprintf("R_PPC_PLTREL24 overflow\n");
338 return B_BAD_DATA;
339
340 case R_PPC_PLT32:
341 REQUIRE_PLT;
342 write_word32(P, L + A);
343 break;
344
345 case R_PPC_PLTREL32:
346 REQUIRE_PLT;
347 write_word32(P, L + A - P);
348 break;
349
350 case R_PPC_PLT16_LO:
351 REQUIRE_PLT;
352 write_half16(P, lo(L + A));
353 break;
354
355 case R_PPC_PLT16_HI:
356 REQUIRE_PLT;
357 write_half16(P, hi(L + A));
358 break;
359
360 case R_PPC_PLT16_HA:
361 write_half16(P, ha(L + A));
362 break;
363
364 case R_PPC_SDAREL16:
365 // TODO: Implement!
366 // if (write_half16_check(P, S + A - _SDA_BASE_))
367 // break;
368 // return B_BAD_DATA;
369 dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet "
370 "supported!\n");
371 return B_ERROR;
372
373 case R_PPC_SECTOFF:
374 if (write_half16_check(P, R + A))
375 break;
376 dprintf("R_PPC_SECTOFF overflow\n");
377 return B_BAD_DATA;
378
379 case R_PPC_SECTOFF_LO:
380 write_half16(P, lo(R + A));
381 break;
382
383 case R_PPC_SECTOFF_HI:
384 write_half16(P, hi(R + A));
385 break;
386
387 case R_PPC_SECTOFF_HA:
388 write_half16(P, ha(R + A));
389 break;
390
391 case R_PPC_ADDR30:
392 write_word30(P, (S + A - P) >> 2);
393 break;
394
395 default:
396 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
397 return B_ERROR;
398 }
399 }
400
401 return B_NO_ERROR;
402 }
403
404