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#ifdef _BOOT_MODE
78status_t
79boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
80	int rel_len)
81#else
82int
83arch_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
92static inline void
93write_32(addr_t P, Elf32_Word value)
94{
95	*(Elf32_Word*)P = value;
96}
97
98
99static inline void
100write_16(addr_t P, Elf32_Word value)
101{
102	// bits 16:29
103	*(Elf32_Half*)P = (Elf32_Half)value;
104}
105
106
107static inline bool
108write_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
118static inline bool
119write_8(addr_t P, Elf32_Word value)
120{
121	// bits 7:0
122	*(uint8 *)P = (uint8)value;
123	return true;
124}
125
126
127static inline bool
128write_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
139status_t
140boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
141	Elf32_Rela *rel, int rel_len)
142#else
143int
144arch_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;
225dprintf("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;
231dprintf("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;
241dprintf("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;
247dprintf("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;
259dprintf("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;
266dprintf("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;
278dprintf("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;
285dprintf("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;
305dprintf("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;
312dprintf("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;
324dprintf("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;
331dprintf("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