xref: /haiku/src/system/runtime_loader/arch/m68k/arch_relocate.cpp (revision a55deaea91d64802ed655d4ffcb41a3519338144)
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 
28 static inline void
29 write_32(addr_t *P, Elf32_Word value)
30 {
31 	*(Elf32_Word*)P = value;
32 }
33 
34 
35 static inline void
36 write_16(addr_t *P, Elf32_Word value)
37 {
38 	// bits 16:29
39 	*(Elf32_Half*)P = (Elf32_Half)value;
40 }
41 
42 
43 static inline bool
44 write_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 
54 static inline bool
55 write_8(addr_t *P, Elf32_Word value)
56 {
57 	// bits 7:0
58 	*(uint8 *)P = (uint8)value;
59 	return true;
60 }
61 
62 
63 static inline bool
64 write_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 
74 static int
75 relocate_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 
274 status_t
275 arch_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