xref: /haiku/src/system/kernel/arch/ppc/arch_elf.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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, 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
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 	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