btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / arch / ppc / arch_elf.cpp
blob47c25a2fe8b7d09a9045771394e137d2b4185b1f
1 /*
2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 * Copyright 2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
10 #ifdef _BOOT_MODE
11 #include <boot/arch.h>
12 #endif
14 #include <KernelExport.h>
16 #include <elf_priv.h>
17 #include <arch/elf.h>
20 #define CHATTY 0
22 #ifdef _BOOT_MODE
23 status_t
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
32 // there are no rel entries in PPC elf
33 return B_NO_ERROR;
37 static inline void
38 write_word32(addr_t P, Elf32_Word value)
40 *(Elf32_Word*)P = value;
44 static inline void
45 write_word30(addr_t P, Elf32_Word value)
47 // bits 0:29
48 *(Elf32_Word*)P = (*(Elf32_Word*)P & 0x3) | (value << 2);
52 static inline bool
53 write_low24_check(addr_t P, Elf32_Word value)
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;
64 static inline bool
65 write_low14_check(addr_t P, Elf32_Word value)
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;
76 static inline void
77 write_half16(addr_t P, Elf32_Word value)
79 // bits 16:29
80 *(Elf32_Half*)P = (Elf32_Half)value;
84 static inline bool
85 write_half16_check(addr_t P, Elf32_Word value)
87 // bits 16:29
88 if ((value & 0xffff0000) && (~value & 0xffff8000))
89 return false;
90 *(Elf32_Half*)P = (Elf32_Half)value;
91 return true;
95 static inline Elf32_Word
96 lo(Elf32_Word value)
98 return (value & 0xffff);
102 static inline Elf32_Word
103 hi(Elf32_Word value)
105 return ((value >> 16) & 0xffff);
109 static inline Elf32_Word
110 ha(Elf32_Word value)
112 return (((value >> 16) + (value & 0x8000 ? 1 : 0)) & 0xffff);
116 #ifdef _BOOT_MODE
117 status_t
118 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
119 Elf32_Rela *rel, int rel_len)
120 #else
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
126 int i;
127 Elf32_Sym *sym;
128 int vlErr;
129 addr_t S = 0; // symbol address
130 addr_t R = 0; // section relative symbol address
132 addr_t G = 0; // GOT address
133 addr_t L = 0; // PLT address
135 #define P ((addr_t)(image->text_region.delta + rel[i].r_offset))
136 #define A ((addr_t)rel[i].r_addend)
137 #define B (image->text_region.delta)
139 // TODO: Get the GOT address!
140 #define REQUIRE_GOT \
141 if (G == 0) { \
142 dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
143 return B_ERROR; \
146 // TODO: Get the PLT address!
147 #define REQUIRE_PLT \
148 if (L == 0) { \
149 dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
150 return B_ERROR; \
153 for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) {
154 #if CHATTY
155 dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
156 ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
157 #endif
158 switch (ELF32_R_TYPE(rel[i].r_info)) {
159 case R_PPC_SECTOFF:
160 case R_PPC_SECTOFF_LO:
161 case R_PPC_SECTOFF_HI:
162 case R_PPC_SECTOFF_HA:
163 dprintf("arch_elf_relocate_rela(): Getting section relative "
164 "symbol addresses not yet supported!\n");
165 return B_ERROR;
167 case R_PPC_ADDR32:
168 case R_PPC_ADDR24:
169 case R_PPC_ADDR16:
170 case R_PPC_ADDR16_LO:
171 case R_PPC_ADDR16_HI:
172 case R_PPC_ADDR16_HA:
173 case R_PPC_ADDR14:
174 case R_PPC_ADDR14_BRTAKEN:
175 case R_PPC_ADDR14_BRNTAKEN:
176 case R_PPC_REL24:
177 case R_PPC_REL14:
178 case R_PPC_REL14_BRTAKEN:
179 case R_PPC_REL14_BRNTAKEN:
180 case R_PPC_GLOB_DAT:
181 case R_PPC_UADDR32:
182 case R_PPC_UADDR16:
183 case R_PPC_REL32:
184 case R_PPC_SDAREL16:
185 case R_PPC_ADDR30:
186 case R_PPC_JMP_SLOT:
187 sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
189 #ifdef _BOOT_MODE
190 vlErr = boot_elf_resolve_symbol(image, sym, &S);
191 #else
192 vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
193 #endif
194 if (vlErr < 0) {
195 dprintf("%s(): Failed to relocate "
196 "entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
197 "addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info),
198 rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
199 rel[i].r_addend);
200 return vlErr;
202 break;
205 switch (ELF32_R_TYPE(rel[i].r_info)) {
206 case R_PPC_NONE:
207 break;
209 case R_PPC_COPY:
210 // TODO: Implement!
211 dprintf("arch_elf_relocate_rela(): R_PPC_COPY not yet "
212 "supported!\n");
213 return B_ERROR;
215 case R_PPC_ADDR32:
216 case R_PPC_GLOB_DAT:
217 case R_PPC_UADDR32:
218 write_word32(P, S + A);
219 break;
221 case R_PPC_ADDR24:
222 if (write_low24_check(P, (S + A) >> 2))
223 break;
224 dprintf("R_PPC_ADDR24 overflow\n");
225 return B_BAD_DATA;
227 case R_PPC_ADDR16:
228 case R_PPC_UADDR16:
229 if (write_half16_check(P, S + A))
230 break;
231 dprintf("R_PPC_ADDR16 overflow\n");
232 return B_BAD_DATA;
234 case R_PPC_ADDR16_LO:
235 write_half16(P, lo(S + A));
236 break;
238 case R_PPC_ADDR16_HI:
239 write_half16(P, hi(S + A));
240 break;
242 case R_PPC_ADDR16_HA:
243 write_half16(P, ha(S + A));
244 break;
246 case R_PPC_ADDR14:
247 case R_PPC_ADDR14_BRTAKEN:
248 case R_PPC_ADDR14_BRNTAKEN:
249 if (write_low14_check(P, (S + A) >> 2))
250 break;
251 dprintf("R_PPC_ADDR14 overflow\n");
252 return B_BAD_DATA;
254 case R_PPC_REL24:
255 if (write_low24_check(P, (S + A - P) >> 2))
256 break;
257 dprintf("R_PPC_REL24 overflow: 0x%lx\n", (S + A - P) >> 2);
258 return B_BAD_DATA;
260 case R_PPC_REL14:
261 case R_PPC_REL14_BRTAKEN:
262 case R_PPC_REL14_BRNTAKEN:
263 if (write_low14_check(P, (S + A - P) >> 2))
264 break;
265 dprintf("R_PPC_REL14 overflow\n");
266 return B_BAD_DATA;
268 case R_PPC_GOT16:
269 REQUIRE_GOT;
270 if (write_half16_check(P, G + A))
271 break;
272 dprintf("R_PPC_GOT16 overflow\n");
273 return B_BAD_DATA;
275 case R_PPC_GOT16_LO:
276 REQUIRE_GOT;
277 write_half16(P, lo(G + A));
278 break;
280 case R_PPC_GOT16_HI:
281 REQUIRE_GOT;
282 write_half16(P, hi(G + A));
283 break;
285 case R_PPC_GOT16_HA:
286 REQUIRE_GOT;
287 write_half16(P, ha(G + A));
288 break;
290 case R_PPC_JMP_SLOT:
292 // If the relative offset is small enough, we fabricate a
293 // relative branch instruction ("b <addr>").
294 addr_t jumpOffset = S - P;
295 if ((jumpOffset & 0xfc000000) != 0
296 && (~jumpOffset & 0xfe000000) != 0) {
297 // Offset > 24 bit.
298 // TODO: Implement!
299 // See System V PPC ABI supplement, p. 5-6!
300 dprintf("arch_elf_relocate_rela(): R_PPC_JMP_SLOT: "
301 "Offsets > 24 bit currently not supported!\n");
302 dprintf("jumpOffset: %p\n", (void*)jumpOffset);
303 return B_ERROR;
304 } else {
305 // Offset <= 24 bit
306 // 0:5 opcode (= 18), 6:29 address, 30 AA, 31 LK
307 // "b" instruction: opcode = 18, AA = 0, LK = 0
308 // address: 24 high-order bits of 26 bit offset
309 *(uint32*)P = 0x48000000 | ((jumpOffset) & 0x03fffffc);
311 break;
314 case R_PPC_RELATIVE:
315 write_word32(P, B + A);
316 break;
318 case R_PPC_LOCAL24PC:
319 // TODO: Implement!
320 // low24*
321 // if (write_low24_check(P, ?)
322 // break;
323 // return B_BAD_DATA;
324 dprintf("arch_elf_relocate_rela(): R_PPC_LOCAL24PC not yet "
325 "supported!\n");
326 return B_ERROR;
328 case R_PPC_REL32:
329 write_word32(P, S + A - P);
330 break;
332 case R_PPC_PLTREL24:
333 REQUIRE_PLT;
334 if (write_low24_check(P, (L + A - P) >> 2))
335 break;
336 dprintf("R_PPC_PLTREL24 overflow\n");
337 return B_BAD_DATA;
339 case R_PPC_PLT32:
340 REQUIRE_PLT;
341 write_word32(P, L + A);
342 break;
344 case R_PPC_PLTREL32:
345 REQUIRE_PLT;
346 write_word32(P, L + A - P);
347 break;
349 case R_PPC_PLT16_LO:
350 REQUIRE_PLT;
351 write_half16(P, lo(L + A));
352 break;
354 case R_PPC_PLT16_HI:
355 REQUIRE_PLT;
356 write_half16(P, hi(L + A));
357 break;
359 case R_PPC_PLT16_HA:
360 write_half16(P, ha(L + A));
361 break;
363 case R_PPC_SDAREL16:
364 // TODO: Implement!
365 // if (write_half16_check(P, S + A - _SDA_BASE_))
366 // break;
367 // return B_BAD_DATA;
368 dprintf("arch_elf_relocate_rela(): R_PPC_SDAREL16 not yet "
369 "supported!\n");
370 return B_ERROR;
372 case R_PPC_SECTOFF:
373 if (write_half16_check(P, R + A))
374 break;
375 dprintf("R_PPC_SECTOFF overflow\n");
376 return B_BAD_DATA;
378 case R_PPC_SECTOFF_LO:
379 write_half16(P, lo(R + A));
380 break;
382 case R_PPC_SECTOFF_HI:
383 write_half16(P, hi(R + A));
384 break;
386 case R_PPC_SECTOFF_HA:
387 write_half16(P, ha(R + A));
388 break;
390 case R_PPC_ADDR30:
391 write_word30(P, (S + A - P) >> 2);
392 break;
394 default:
395 dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
396 return B_ERROR;
400 return B_NO_ERROR;