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