xref: /haiku/src/system/kernel/arch/ppc/arch_elf.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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
24 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image,
25 	struct Elf32_Rel *rel, int rel_len)
26 #else
27 int
28 arch_elf_relocate_rel(struct elf_image_info *image,
29 	struct elf_image_info *resolve_image, struct 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
38 write_word32(addr_t P, Elf32_Word value)
39 {
40 	*(Elf32_Word*)P = value;
41 }
42 
43 
44 static inline void
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
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
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
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
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
96 lo(Elf32_Word value)
97 {
98 	return (value & 0xffff);
99 }
100 
101 
102 static inline Elf32_Word
103 hi(Elf32_Word value)
104 {
105 	return ((value >> 16) & 0xffff);
106 }
107 
108 
109 static inline Elf32_Word
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
118 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
119 	struct 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, struct Elf32_Rela *rel, int rel_len)
124 #endif
125 {
126 	int i;
127 	struct Elf32_Sym *sym;
128 	int vlErr;
129 	addr_t S = 0;	// symbol address
130 	addr_t R = 0;	// section relative symbol address
131 
132 	addr_t G = 0;	// GOT address
133 	addr_t L = 0;	// PLT address
134 
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)
138 
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;	\
144 		}
145 
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;	\
151 		}
152 
153 	for (i = 0; i * (int)sizeof(struct 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;
166 
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));
188 
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;
201 				}
202 				break;
203 		}
204 
205 		switch (ELF32_R_TYPE(rel[i].r_info)) {
206 			case R_PPC_NONE:
207 				break;
208 
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;
214 
215 			case R_PPC_ADDR32:
216 			case R_PPC_GLOB_DAT:
217 			case R_PPC_UADDR32:
218 				write_word32(P, S + A);
219 				break;
220 
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;
226 
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;
233 
234 			case R_PPC_ADDR16_LO:
235 				write_half16(P, lo(S + A));
236 				break;
237 
238 			case R_PPC_ADDR16_HI:
239 				write_half16(P, hi(S + A));
240 				break;
241 
242 			case R_PPC_ADDR16_HA:
243 				write_half16(P, ha(S + A));
244 				break;
245 
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;
253 
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;
259 
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;
267 
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;
274 
275 			case R_PPC_GOT16_LO:
276 				REQUIRE_GOT;
277 				write_half16(P, lo(G + A));
278 				break;
279 
280 			case R_PPC_GOT16_HI:
281 				REQUIRE_GOT;
282 				write_half16(P, hi(G + A));
283 				break;
284 
285 			case R_PPC_GOT16_HA:
286 				REQUIRE_GOT;
287 				write_half16(P, ha(G + A));
288 				break;
289 
290 			case R_PPC_JMP_SLOT:
291 			{
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);
310 				}
311 				break;
312 			}
313 
314 			case R_PPC_RELATIVE:
315 				write_word32(P, B + A);
316 				break;
317 
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;
327 
328 			case R_PPC_REL32:
329 				write_word32(P, S + A - P);
330 				break;
331 
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;
338 
339 			case R_PPC_PLT32:
340 				REQUIRE_PLT;
341 				write_word32(P, L + A);
342 				break;
343 
344 			case R_PPC_PLTREL32:
345 				REQUIRE_PLT;
346 				write_word32(P, L + A - P);
347 				break;
348 
349 			case R_PPC_PLT16_LO:
350 				REQUIRE_PLT;
351 				write_half16(P, lo(L + A));
352 				break;
353 
354 			case R_PPC_PLT16_HI:
355 				REQUIRE_PLT;
356 				write_half16(P, hi(L + A));
357 				break;
358 
359 			case R_PPC_PLT16_HA:
360 				write_half16(P, ha(L + A));
361 				break;
362 
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;
371 
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;
377 
378 			case R_PPC_SECTOFF_LO:
379 				write_half16(P, lo(R + A));
380 				break;
381 
382 			case R_PPC_SECTOFF_HI:
383 				write_half16(P, hi(R + A));
384 				break;
385 
386 			case R_PPC_SECTOFF_HA:
387 				write_half16(P, ha(R + A));
388 				break;
389 
390 			case R_PPC_ADDR30:
391 				write_word30(P, (S + A - P) >> 2);
392 				break;
393 
394 			default:
395 				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
396 				return B_ERROR;
397 		}
398 	}
399 
400 	return B_NO_ERROR;
401 }
402 
403