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
34static 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
78#ifdef _BOOT_MODE
79bool boot_arch_elf_arch_compat(struct elf_image_arch* hostArch,
80	struct elf_image_arch* imageArch)
81#else
82bool arch_elf_arch_compat(struct elf_image_arch* hostArch,
83	struct elf_image_arch* imageArch)
84#endif
85{
86	if (hostArch->osabi != imageArch->osabi)
87		return false;
88
89	if (hostArch->osabi_version != imageArch->osabi_version)
90		return false;
91
92	if (hostArch->word_size != imageArch->word_size)
93		return false;
94
95	if (hostArch->byte_order != imageArch->byte_order)
96		return false;
97
98	if (hostArch->machine == imageArch->machine)
99		return false;
100
101	return true;
102}
103
104
105#ifdef _BOOT_MODE
106uint32_t boot_arch_elf_score_image_arch(struct elf_image_arch *arch)
107#else
108uint32_t arch_elf_score_image_arch(struct elf_image_arch *arch)
109#endif
110{
111	if (arch->osabi != ELFOSABI_HAIKU)
112		return 0;
113
114	if (arch->osabi_version != 0)
115		return 0;
116
117	if (arch->word_size != ELF_CLASS)
118		return 0;
119
120	if (arch->byte_order != ELF_DATA)
121		return 0;
122
123	if (!ELF_MACHINE_OK(arch->machine))
124		return 0;
125}
126
127
128#ifdef _BOOT_MODE
129status_t
130boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image,
131	struct Elf32_Rel *rel, int rel_len)
132#else
133int
134arch_elf_relocate_rel(struct elf_image_info *image,
135	struct elf_image_info *resolve_image, struct Elf32_Rel *rel, int rel_len)
136#endif
137{
138	// there are no rel entries in M68K elf
139	return B_NO_ERROR;
140}
141
142
143static inline void
144write_32(addr_t P, Elf32_Word value)
145{
146	*(Elf32_Word*)P = value;
147}
148
149
150static inline void
151write_16(addr_t P, Elf32_Word value)
152{
153	// bits 16:29
154	*(Elf32_Half*)P = (Elf32_Half)value;
155}
156
157
158static inline bool
159write_16_check(addr_t P, Elf32_Word value)
160{
161	// bits 15:0
162	if ((value & 0xffff0000) && (~value & 0xffff8000))
163		return false;
164	*(Elf32_Half*)P = (Elf32_Half)value;
165	return true;
166}
167
168
169static inline bool
170write_8(addr_t P, Elf32_Word value)
171{
172	// bits 7:0
173	*(uint8 *)P = (uint8)value;
174	return true;
175}
176
177
178static inline bool
179write_8_check(addr_t P, Elf32_Word value)
180{
181	// bits 7:0
182	if ((value & 0xffffff00) && (~value & 0xffffff80))
183		return false;
184	*(uint8 *)P = (uint8)value;
185	return true;
186}
187
188
189#ifdef _BOOT_MODE
190status_t
191boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
192	struct Elf32_Rela *rel, int rel_len)
193#else
194int
195arch_elf_relocate_rela(struct elf_image_info *image,
196	struct elf_image_info *resolve_image, struct Elf32_Rela *rel, int rel_len)
197#endif
198{
199	int i;
200	struct Elf32_Sym *sym;
201	int vlErr;
202	addr_t S = 0;	// symbol address
203	addr_t R = 0;	// section relative symbol address
204
205	addr_t G = 0;	// GOT address
206	addr_t L = 0;	// PLT address
207
208	#define P	((addr_t)(image->text_region.delta + rel[i].r_offset))
209	#define A	((addr_t)rel[i].r_addend)
210	#define B	(image->text_region.delta)
211
212	// TODO: Get the GOT address!
213	#define REQUIRE_GOT	\
214		if (G == 0) {	\
215			dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \
216			return B_ERROR;	\
217		}
218
219	// TODO: Get the PLT address!
220	#define REQUIRE_PLT	\
221		if (L == 0) {	\
222			dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \
223			return B_ERROR;	\
224		}
225
226	for (i = 0; i * (int)sizeof(struct Elf32_Rela) < rel_len; i++) {
227#if CHATTY
228		dprintf("looking at rel type %d, offset 0x%lx, sym 0x%lx, addend 0x%lx\n",
229			ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, ELF32_R_SYM(rel[i].r_info), rel[i].r_addend);
230#endif
231		switch (ELF32_R_TYPE(rel[i].r_info)) {
232			case R_68K_32:
233			case R_68K_16:
234			case R_68K_8:
235			case R_68K_PC32:
236			case R_68K_PC16:
237			case R_68K_PC8:
238			case R_68K_GLOB_DAT:
239			case R_68K_JMP_SLOT:
240				sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
241
242#ifdef _BOOT_MODE
243				vlErr = boot_elf_resolve_symbol(image, sym, &S);
244#else
245				vlErr = elf_resolve_symbol(image, sym, resolve_image, &S);
246#endif
247				if (vlErr < 0) {
248					dprintf("%s(): Failed to relocate "
249						"entry index %d, rel type %d, offset 0x%lx, sym 0x%lx, "
250						"addend 0x%lx\n", __FUNCTION__, i, ELF32_R_TYPE(rel[i].r_info),
251						rel[i].r_offset, ELF32_R_SYM(rel[i].r_info),
252						rel[i].r_addend);
253					return vlErr;
254				}
255				break;
256		}
257
258		switch (ELF32_R_TYPE(rel[i].r_info)) {
259			case R_68K_NONE:
260				break;
261
262			case R_68K_COPY:
263				// TODO: Implement!
264				dprintf("arch_elf_relocate_rela(): R_68K_COPY not yet "
265					"supported!\n");
266				return B_ERROR;
267
268			case R_68K_32:
269			case R_68K_GLOB_DAT:
270				write_32(P, S + A);
271				break;
272
273			case R_68K_16:
274				if (write_16_check(P, S + A))
275					break;
276dprintf("R_68K_16 overflow\n");
277				return B_BAD_DATA;
278
279			case R_68K_8:
280				if (write_8_check(P, S + A))
281					break;
282dprintf("R_68K_8 overflow\n");
283				return B_BAD_DATA;
284
285			case R_68K_PC32:
286				write_32(P, (S + A - P));
287				break;
288
289			case R_68K_PC16:
290				if (write_16_check(P, (S + A - P)))
291					break;
292dprintf("R_68K_PC16 overflow\n");
293				return B_BAD_DATA;
294
295			case R_68K_PC8:
296				if (write_8(P, (S + A - P)))
297					break;
298dprintf("R_68K_PC8 overflow\n");
299				return B_BAD_DATA;
300
301			case R_68K_GOT32:
302				REQUIRE_GOT;
303				write_32(P, (G + A - P));
304				break;
305
306			case R_68K_GOT16:
307				REQUIRE_GOT;
308				if (write_16_check(P, (G + A - P)))
309					break;
310dprintf("R_68K_GOT16 overflow\n");
311				return B_BAD_DATA;
312
313			case R_68K_GOT8:
314				REQUIRE_GOT;
315				if (write_8_check(P, (G + A - P)))
316					break;
317dprintf("R_68K_GOT8 overflow\n");
318				return B_BAD_DATA;
319
320			case R_68K_GOT32O:
321				REQUIRE_GOT;
322				write_32(P, (G + A));
323				break;
324
325			case R_68K_GOT16O:
326				REQUIRE_GOT;
327				if (write_16_check(P, (G + A)))
328					break;
329dprintf("R_68K_GOT16 overflow\n");
330				return B_BAD_DATA;
331
332			case R_68K_GOT8O:
333				REQUIRE_GOT;
334				if (write_8_check(P, (G + A)))
335					break;
336dprintf("R_68K_GOT8 overflow\n");
337				return B_BAD_DATA;
338
339			case R_68K_JMP_SLOT:
340				write_32(P, (G + A));
341				break;
342
343			case R_68K_RELATIVE:
344				write_32(P, B + A);
345				break;
346
347			case R_68K_PLT32:
348				REQUIRE_PLT;
349				write_32(P, (L + A - P));
350				break;
351
352			case R_68K_PLT16:
353				REQUIRE_PLT;
354				if (write_16_check(P, (L + A - P)))
355					break;
356dprintf("R_68K_PLT16 overflow\n");
357				return B_BAD_DATA;
358
359			case R_68K_PLT8:
360				REQUIRE_PLT;
361				if (write_8_check(P, (L + A - P)))
362					break;
363dprintf("R_68K_PLT8 overflow\n");
364				return B_BAD_DATA;
365
366			case R_68K_PLT32O:
367				REQUIRE_PLT;
368				write_32(P, (L + A));
369				break;
370
371			case R_68K_PLT16O:
372				REQUIRE_PLT;
373				if (write_16_check(P, (L + A)))
374					break;
375dprintf("R_68K_PLT16O overflow\n");
376				return B_BAD_DATA;
377
378			case R_68K_PLT8O:
379				REQUIRE_PLT;
380				if (write_8_check(P, (L + A)))
381					break;
382dprintf("R_68K_PLT8O overflow\n");
383				return B_BAD_DATA;
384
385			default:
386				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info));
387				return B_ERROR;
388		}
389	}
390
391	return B_NO_ERROR;
392}
393
394
395
396