1/*
2 * Copyright 2003-2006, Axel D��rfler, axeld@pinc-software.de
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Copyright 2002, Manuel J. Petit. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
9
10
11#include "runtime_loader_private.h"
12
13#include <runtime_loader.h>
14
15#include <string.h>
16#include <stdio.h>
17#include <stdlib.h>
18
19
20//#define TRACE_RLD
21#ifdef TRACE_RLD
22#	define TRACE(x) dprintf x
23#else
24#	define TRACE(x) ;
25#endif
26
27
28static inline void
29write_32(addr_t *P, Elf32_Word value)
30{
31	*(Elf32_Word*)P = value;
32}
33
34
35static inline void
36write_16(addr_t *P, Elf32_Word value)
37{
38	// bits 16:29
39	*(Elf32_Half*)P = (Elf32_Half)value;
40}
41
42
43static inline bool
44write_16_check(addr_t *P, Elf32_Word value)
45{
46	// bits 15:0
47	if ((value & 0xffff0000) && (~value & 0xffff8000))
48		return false;
49	*(Elf32_Half*)P = (Elf32_Half)value;
50	return true;
51}
52
53
54static inline bool
55write_8(addr_t *P, Elf32_Word value)
56{
57	// bits 7:0
58	*(uint8 *)P = (uint8)value;
59	return true;
60}
61
62
63static inline bool
64write_8_check(addr_t *P, Elf32_Word value)
65{
66	// bits 7:0
67	if ((value & 0xffffff00) && (~value & 0xffffff80))
68		return false;
69	*(uint8 *)P = (uint8)value;
70	return true;
71}
72
73
74static int
75relocate_rela(image_t *rootImage, image_t *image, Elf32_Rela *rel, int rel_len,
76	SymbolLookupCache* cache)
77{
78	int i;
79	addr_t S;
80	addr_t final_val;
81
82# define P	((addr_t *)(image->regions[0].delta + rel[i].r_offset))
83//# define A	(*(P))
84#define A	((addr_t)rel[i].r_addend)
85# define B	(image->regions[0].delta)
86
87	for (i = 0; i * (int)sizeof(Elf32_Rel) < rel_len; i++) {
88		unsigned type = ELF32_R_TYPE(rel[i].r_info);
89
90		switch (type) {
91			case R_68K_32:
92			case R_68K_16:
93			case R_68K_8:
94			case R_68K_PC32:
95			case R_68K_PC16:
96			case R_68K_PC8:
97			case R_68K_GLOB_DAT:
98			case R_68K_JMP_SLOT:
99			{
100				Elf32_Sym *sym;
101				status_t status;
102				sym = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
103
104				status = resolve_symbol(rootImage, image, sym, cache, &S);
105				if (status < B_OK) {
106					TRACE(("resolve symbol \"%s\" returned: %ld\n",
107						SYMNAME(image, sym), status));
108					printf("resolve symbol \"%s\" returned: %ld\n",
109						SYMNAME(image, sym), status);
110					return status;
111				}
112			}
113		}
114		switch (type) {
115			case R_68K_NONE:
116				continue;
117			case R_68K_32:
118				write_32(P, S + A);
119				break;
120			case R_68K_16:
121				if (write_16_check(P, S + A))
122					break;
123				TRACE(("R_68K_16 overflow\n"));
124				return B_BAD_DATA;
125
126			case R_68K_8:
127				if (write_8_check(P, S + A))
128					break;
129				TRACE(("R_68K_8 overflow\n"));
130				return B_BAD_DATA;
131
132			case R_68K_PC32:
133				write_32(P, (S + A - (addr_t)P));
134				break;
135
136#if 0
137			case R_68K_PC16:
138				if (write_16_check(P, (S + A - P)))
139					break;
140				TRACE(("R_68K_PC16 overflow\n"));
141				return B_BAD_DATA;
142
143			case R_68K_PC8:
144				if (write_8(P, (S + A - P)))
145					break;
146				TRACE(("R_68K_PC8 overflow\n"));
147				return B_BAD_DATA;
148
149			case R_68K_GOT32:
150				REQUIRE_GOT;
151				write_32(P, (G + A - P));
152				break;
153
154			case R_68K_GOT16:
155				REQUIRE_GOT;
156				if (write_16_check(P, (G + A - P)))
157					break;
158				TRACE(("R_68K_GOT16 overflow\n"));
159				return B_BAD_DATA;
160
161			case R_68K_GOT8:
162				REQUIRE_GOT;
163				if (write_8_check(P, (G + A - P)))
164					break;
165				TRACE(("R_68K_GOT8 overflow\n"));
166				return B_BAD_DATA;
167
168			case R_68K_GOT32O:
169				REQUIRE_GOT;
170				write_32(P, (G + A));
171				break;
172
173			case R_68K_GOT16O:
174				REQUIRE_GOT;
175				if (write_16_check(P, (G + A)))
176					break;
177				TRACE(("R_68K_GOT16 overflow\n"));
178				return B_BAD_DATA;
179
180			case R_68K_GOT8O:
181				REQUIRE_GOT;
182				if (write_8_check(P, (G + A)))
183					break;
184				TRACE(("R_68K_GOT8 overflow\n"));
185				return B_BAD_DATA;
186
187			case R_68K_PLT32:
188				REQUIRE_PLT;
189				write_32(P, (L + A - P));
190				break;
191
192			case R_68K_PLT16:
193				REQUIRE_PLT;
194				if (write_16_check(P, (L + A - P)))
195					break;
196				TRACE(("R_68K_PLT16 overflow\n"));
197				return B_BAD_DATA;
198
199			case R_68K_PLT8:
200				REQUIRE_PLT;
201				if (write_8_check(P, (L + A - P)))
202					break;
203				TRACE(("R_68K_PLT8 overflow\n"));
204				return B_BAD_DATA;
205
206			case R_68K_PLT32O:
207				REQUIRE_PLT;
208				write_32(P, (L + A));
209				break;
210
211			case R_68K_PLT16O:
212				REQUIRE_PLT;
213				if (write_16_check(P, (L + A)))
214					break;
215				TRACE(("R_68K_PLT16O overflow\n"));
216				return B_BAD_DATA;
217
218			case R_68K_PLT8O:
219				REQUIRE_PLT;
220				if (write_8_check(P, (L + A)))
221					break;
222				TRACE(("R_68K_PLT8O overflow\n"));
223				return B_BAD_DATA;
224			case R_386_GOT32:
225				final_val = G + A;
226				break;
227			case R_386_PLT32:
228				final_val = L + A - (addr_t)P;
229				break;
230#endif
231			case R_68K_COPY:
232				/* what ? */
233				continue;
234			case R_68K_GLOB_DAT:
235				write_32(P, S/* + A*/);
236				break;
237			case R_68K_JMP_SLOT:
238				//XXX ? write_32(P, (G + A));
239				write_32(P, S);
240				break;
241#if 0
242			case R_386_JMP_SLOT:
243				write_32(P, S);
244				break;
245#endif
246			case R_68K_RELATIVE:
247				write_32(P, B + A);
248				break;
249
250#if 0
251			case R_386_GOTOFF:
252				final_val = S + A - GOT;
253				break;
254			case R_386_GOTPC:
255				final_val = GOT + A - P;
256				break;
257#endif
258			default:
259				TRACE(("unhandled relocation type %d\n", ELF32_R_TYPE(rel[i].r_info)));
260				return B_NOT_ALLOWED;
261		}
262
263		*P = final_val;
264	}
265
266# undef P
267# undef A
268# undef B
269
270	return B_NO_ERROR;
271}
272
273
274status_t
275arch_relocate_image(image_t *rootImage, image_t *image,
276	SymbolLookupCache* cache)
277{
278	status_t status;
279
280	// deal with the rels first
281	if (image->rel) {
282		TRACE(("RELA relocations not supported\n"));
283		return EOPNOTSUPP;
284	}
285
286	if (image->pltrel) {
287		TRACE(("RELA relocations not supported\n"));
288		return EOPNOTSUPP;
289#if 0
290		status = relocate_rel(rootImage, image, image->pltrel,
291			image->pltrel_len);
292		if (status < B_OK)
293			return status;
294#endif
295	}
296
297	if (image->rela) {
298		status = relocate_rela(rootImage, image, image->rela, image->rela_len,
299			cache);
300		//int i;
301		if (status < B_OK)
302			return status;
303		//TRACE(("RELA relocations not supported\n"));
304		//return EOPNOTSUPP;
305
306		//for (i = 1; i * (int)sizeof(Elf32_Rela) < image->rela_len; i++) {
307		//	printf("rela: type %d\n", ELF32_R_TYPE(image->rela[i].r_info));
308		//}
309	}
310
311#if 0
312	if (image->pltrela) {
313		status = relocate_rela(rootImage, image, image->pltrela,
314			image->pltrela_len);
315		if (status < B_OK)
316			return status;
317	}
318#endif
319
320	return B_OK;
321}
322