xref: /haiku/src/system/kernel/arch/m68k/arch_elf.cpp (revision ae2049aa4f7f2ad6f5c6337a2e1875ab376bbd64)
1 /*
2  * Copyright 2007, François Revol, revol@free.fr.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
6  * All rights reserved. Distributed under the terms of the MIT License.
7  *
8  *
9  * Copyright 2002, Travis Geiselbrecht. All rights reserved.
10  * Distributed under the terms of the NewOS License.
11  */
12 
13 #ifdef _BOOT_MODE
14 #include <boot/arch.h>
15 #endif
16 
17 #include <KernelExport.h>
18 
19 #include <elf_priv.h>
20 #include <arch/elf.h>
21 
22 
23 //#define TRACE_ARCH_ELF
24 #ifdef TRACE_ARCH_ELF
25 #	define TRACE(x) dprintf x
26 #	define CHATTY 1
27 #else
28 #	define TRACE(x) ;
29 #	define CHATTY 0
30 #endif
31 
32 
33 #ifdef TRACE_ARCH_ELF
34 static const char *kRelocations[] = {
35 	"R_68K_NONE",
36 	"R_68K_32",	/* Direct 32 bit  */
37 	"R_68K_16",	/* Direct 16 bit  */
38 	"R_68K_8",	/* Direct 8 bit  */
39 	"R_68K_PC32",	/* PC relative 32 bit */
40 	"R_68K_PC16",	/* PC relative 16 bit */
41 	"R_68K_PC8",	/* PC relative 8 bit */
42 	"R_68K_GOT32",	/* 32 bit PC relative GOT entry */
43 	"R_68K_GOT16",	/* 16 bit PC relative GOT entry */
44 	"R_68K_GOT8",	/* 8 bit PC relative GOT entry */
45 	"R_68K_GOT32O",	/* 32 bit GOT offset */
46 	"R_68K_GOT16O",	/* 16 bit GOT offset */
47 	"R_68K_GOT8O",	/* 8 bit GOT offset */
48 	"R_68K_PLT32",	/* 32 bit PC relative PLT address */
49 	"R_68K_PLT16",	/* 16 bit PC relative PLT address */
50 	"R_68K_PLT8",	/* 8 bit PC relative PLT address */
51 	"R_68K_PLT32O",	/* 32 bit PLT offset */
52 	"R_68K_PLT16O",	/* 16 bit PLT offset */
53 	"R_68K_PLT8O",	/* 8 bit PLT offset */
54 	"R_68K_COPY",	/* Copy symbol at runtime */
55 	"R_68K_GLOB_DAT",	/* Create GOT entry */
56 	"R_68K_JMP_SLOT",	/* Create PLT entry */
57 	"R_68K_RELATIVE",	/* Adjust by program base */
58 	/* These are GNU extensions to enable C++ vtable garbage collection.  */
59 	"R_68K_GNU_VTINHERIT",
60 	"R_68K_GNU_VTENTRY",
61 #if 0
62 	"R_386_NONE",
63 	"R_386_32",			/* add symbol value */
64 	"R_386_PC32",		/* add PC relative symbol value */
65 	"R_386_GOT32",		/* add PC relative GOT offset */
66 	"R_386_PLT32",		/* add PC relative PLT offset */
67 	"R_386_COPY",		/* copy data from shared object */
68 	"R_386_GLOB_DAT",	/* set GOT entry to data address */
69 	"R_386_JMP_SLOT",	/* set GOT entry to code address */
70 	"R_386_RELATIVE",	/* add load address of shared object */
71 	"R_386_GOTOFF",		/* add GOT relative symbol address */
72 	"R_386_GOTPC",		/* add PC relative GOT table address */
73 #endif
74 };
75 #endif
76 
77 #ifdef _BOOT_MODE
78 status_t
79 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
80 	int rel_len)
81 #else
82 int
83 arch_elf_relocate_rel(struct elf_image_info *image,
84 	struct elf_image_info *resolve_image, Elf32_Rel *rel, int rel_len)
85 #endif
86 {
87 	// there are no rel entries in M68K elf
88 	return B_NO_ERROR;
89 }
90 
91 
92 static inline void
93 write_32(addr_t P, Elf32_Word value)
94 {
95 	*(Elf32_Word*)P = value;
96 }
97 
98 
99 static inline void
100 write_16(addr_t P, Elf32_Word value)
101 {
102 	// bits 16:29
103 	*(Elf32_Half*)P = (Elf32_Half)value;
104 }
105 
106 
107 static inline bool
108 write_16_check(addr_t P, Elf32_Word value)
109 {
110 	// bits 15:0
111 	if ((value & 0xffff0000) && (~value & 0xffff8000))
112 		return false;
113 	*(Elf32_Half*)P = (Elf32_Half)value;
114 	return true;
115 }
116 
117 
118 static inline bool
119 write_8(addr_t P, Elf32_Word value)
120 {
121 	// bits 7:0
122 	*(uint8 *)P = (uint8)value;
123 	return true;
124 }
125 
126 
127 static inline bool
128 write_8_check(addr_t P, Elf32_Word value)
129 {
130 	// bits 7:0
131 	if ((value & 0xffffff00) && (~value & 0xffffff80))
132 		return false;
133 	*(uint8 *)P = (uint8)value;
134 	return true;
135 }
136 
137 
138 #ifdef _BOOT_MODE
139 status_t
140 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
141 	Elf32_Rela *rel, int rel_len)
142 #else
143 int
144 arch_elf_relocate_rela(struct elf_image_info *image,
145 	struct elf_image_info *resolve_image, Elf32_Rela *rel, int rel_len)
146 #endif
147 {
148 	int i;
149 	Elf32_Sym *sym;
150 	int vlErr;
151 	elf_addr S = 0;	// symbol address
152 	addr_t R = 0;	// section relative symbol address
153 
154 	addr_t G = 0;	// GOT address
155 	addr_t L = 0;	// PLT address
156 
157 	#define P	((addr_t)(image->text_region.delta + rel[i].r_offset))
158 	#define A	((addr_t)rel[i].r_addend)
159 	#define B	(image->text_region.delta)
160 
161 	// TODO: Get the GOT address!
162 	#define REQUIRE_GOT	\
163 		if (G == 0) {	\
164 			dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
165 			return B_ERROR;	\
166 		}
167 
168 	// TODO: Get the PLT address!
169 	#define REQUIRE_PLT	\
170 		if (L == 0) {	\
171 			dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
172 			return B_ERROR;	\
173 		}
174 
175 	for (i = 0; i * (int)sizeof(Elf32_Rela) < rel_len; i++) {
176 #if CHATTY
177 		dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
178 			ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
179 #endif
180 		switch (ELF32_R_TYPE(rel[i].r_info)) {
181 			case R_68K_32:
182 			case R_68K_16:
183 			case R_68K_8:
184 			case R_68K_PC32:
185 			case R_68K_PC16:
186 			case R_68K_PC8:
187 			case R_68K_GLOB_DAT:
188 			case R_68K_JMP_SLOT:
189 				sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
190 
191 #ifdef _BOOT_MODE
192 				vlErr = boot_elf_resolve_symbol(image, sym, &S);
193 #else
194 				vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
195 #endif
196 				if (vlErr < 0) {
197 					dprintf("%s(): Failed to relocate "
198 						"entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
199 						"addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info),
200 						rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
201 						rel[i].r_addend);
202 					return vlErr;
203 				}
204 				break;
205 		}
206 
207 		switch (ELF32_R_TYPE(rel[i].r_info)) {
208 			case R_68K_NONE:
209 				break;
210 
211 			case R_68K_COPY:
212 				// TODO: Implement!
213 				dprintf("arch_elf_relocate_rela(): R_68K_COPY not yet "
214 					"supported!\n");
215 				return B_ERROR;
216 
217 			case R_68K_32:
218 			case R_68K_GLOB_DAT:
219 				write_32(P, S + A);
220 				break;
221 
222 			case R_68K_16:
223 				if (write_16_check(P, S + A))
224 					break;
225 dprintf("R_68K_16 overflow\n");
226 				return B_BAD_DATA;
227 
228 			case R_68K_8:
229 				if (write_8_check(P, S + A))
230 					break;
231 dprintf("R_68K_8 overflow\n");
232 				return B_BAD_DATA;
233 
234 			case R_68K_PC32:
235 				write_32(P, (S + A - P));
236 				break;
237 
238 			case R_68K_PC16:
239 				if (write_16_check(P, (S + A - P)))
240 					break;
241 dprintf("R_68K_PC16 overflow\n");
242 				return B_BAD_DATA;
243 
244 			case R_68K_PC8:
245 				if (write_8(P, (S + A - P)))
246 					break;
247 dprintf("R_68K_PC8 overflow\n");
248 				return B_BAD_DATA;
249 
250 			case R_68K_GOT32:
251 				REQUIRE_GOT;
252 				write_32(P, (G + A - P));
253 				break;
254 
255 			case R_68K_GOT16:
256 				REQUIRE_GOT;
257 				if (write_16_check(P, (G + A - P)))
258 					break;
259 dprintf("R_68K_GOT16 overflow\n");
260 				return B_BAD_DATA;
261 
262 			case R_68K_GOT8:
263 				REQUIRE_GOT;
264 				if (write_8_check(P, (G + A - P)))
265 					break;
266 dprintf("R_68K_GOT8 overflow\n");
267 				return B_BAD_DATA;
268 
269 			case R_68K_GOT32O:
270 				REQUIRE_GOT;
271 				write_32(P, (G + A));
272 				break;
273 
274 			case R_68K_GOT16O:
275 				REQUIRE_GOT;
276 				if (write_16_check(P, (G + A)))
277 					break;
278 dprintf("R_68K_GOT16 overflow\n");
279 				return B_BAD_DATA;
280 
281 			case R_68K_GOT8O:
282 				REQUIRE_GOT;
283 				if (write_8_check(P, (G + A)))
284 					break;
285 dprintf("R_68K_GOT8 overflow\n");
286 				return B_BAD_DATA;
287 
288 			case R_68K_JMP_SLOT:
289 				write_32(P, S + A);
290 				break;
291 
292 			case R_68K_RELATIVE:
293 				write_32(P, B + A);
294 				break;
295 
296 			case R_68K_PLT32:
297 				REQUIRE_PLT;
298 				write_32(P, (L + A - P));
299 				break;
300 
301 			case R_68K_PLT16:
302 				REQUIRE_PLT;
303 				if (write_16_check(P, (L + A - P)))
304 					break;
305 dprintf("R_68K_PLT16 overflow\n");
306 				return B_BAD_DATA;
307 
308 			case R_68K_PLT8:
309 				REQUIRE_PLT;
310 				if (write_8_check(P, (L + A - P)))
311 					break;
312 dprintf("R_68K_PLT8 overflow\n");
313 				return B_BAD_DATA;
314 
315 			case R_68K_PLT32O:
316 				REQUIRE_PLT;
317 				write_32(P, (L + A));
318 				break;
319 
320 			case R_68K_PLT16O:
321 				REQUIRE_PLT;
322 				if (write_16_check(P, (L + A)))
323 					break;
324 dprintf("R_68K_PLT16O overflow\n");
325 				return B_BAD_DATA;
326 
327 			case R_68K_PLT8O:
328 				REQUIRE_PLT;
329 				if (write_8_check(P, (L + A)))
330 					break;
331 dprintf("R_68K_PLT8O overflow\n");
332 				return B_BAD_DATA;
333 
334 			default:
335 				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
336 				return B_ERROR;
337 		}
338 	}
339 
340 	return B_NO_ERROR;
341 }
342 
343 
344 
345