xref: /haiku/src/system/kernel/arch/x86/arch_elf.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2004-2018, Haiku Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Copyright 2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 
10 #ifdef _BOOT_MODE
11 #	include <boot/arch.h>
12 #endif
13 
14 #include <KernelExport.h>
15 
16 #include <elf_priv.h>
17 #include <arch/elf.h>
18 
19 
20 //#define TRACE_ARCH_ELF
21 #ifdef TRACE_ARCH_ELF
22 #	define TRACE(x) dprintf x
23 #else
24 #	define TRACE(x) ;
25 #endif
26 
27 
28 #ifndef _BOOT_MODE
29 static bool
30 is_in_image(struct elf_image_info *image, addr_t address)
31 {
32 	return (address >= image->text_region.start
33 			&& address < image->text_region.start + image->text_region.size)
34 		|| (address >= image->data_region.start
35 			&& address < image->data_region.start + image->data_region.size);
36 }
37 #endif	// !_BOOT_MODE
38 
39 
40 #if !defined(__x86_64__) || defined(ELF32_COMPAT)	\
41 	 || (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF32))
42 
43 
44 #ifdef TRACE_ARCH_ELF
45 static const char *kRelocations[] = {
46 	"R_386_NONE",
47 	"R_386_32",			/* add symbol value */
48 	"R_386_PC32",		/* add PC relative symbol value */
49 	"R_386_GOT32",		/* add PC relative GOT offset */
50 	"R_386_PLT32",		/* add PC relative PLT offset */
51 	"R_386_COPY",		/* copy data from shared object */
52 	"R_386_GLOB_DAT",	/* set GOT entry to data address */
53 	"R_386_JMP_SLOT",	/* set GOT entry to code address */
54 	"R_386_RELATIVE",	/* add load address of shared object */
55 	"R_386_GOTOFF",		/* add GOT relative symbol address */
56 	"R_386_GOTPC",		/* add PC relative GOT table address */
57 };
58 #endif
59 
60 
61 #ifdef _BOOT_MODE
62 status_t
63 boot_arch_elf_relocate_rel(struct preloaded_elf32_image *image, Elf32_Rel *rel,
64 	int relLength)
65 #else
66 int
67 arch_elf_relocate_rel(struct elf_image_info *image,
68 	struct elf_image_info *resolveImage, Elf32_Rel *rel, int relLength)
69 #endif
70 {
71 	Elf32_Addr S;
72 	uint32 A;
73 	uint32 P;
74 	uint32 finalAddress;
75 	uint32 *resolveAddress;
76 	int i;
77 
78 	S = A = P = 0;
79 
80 	for (i = 0; i * (int)sizeof(Elf32_Rel) < relLength; i++) {
81 		TRACE(("looking at rel type %s, offset 0x%" B_PRIx32 "\n",
82 			kRelocations[ELF32_R_TYPE(rel[i].r_info)], rel[i].r_offset));
83 
84 		// calc S
85 		switch (ELF32_R_TYPE(rel[i].r_info)) {
86 			case R_386_32:
87 			case R_386_PC32:
88 			case R_386_GLOB_DAT:
89 			case R_386_JMP_SLOT:
90 			case R_386_GOTOFF:
91 			{
92 				Elf32_Sym *symbol;
93 				status_t status;
94 
95 				symbol = SYMBOL(image, ELF32_R_SYM(rel[i].r_info));
96 
97 #ifdef _BOOT_MODE
98 				status = boot_elf_resolve_symbol(image, symbol, &S);
99 #else
100 				status = elf_resolve_symbol(image, symbol, resolveImage, &S);
101 #endif
102 				if (status < B_OK)
103 					return status;
104 #ifndef _BOOT_MODE
105 				TRACE(("S 0x%08" B_PRIx32 " (%s)\n", S, SYMNAME(image, symbol)));
106 #endif
107 			}
108 		}
109 		// calc A
110 		switch (ELF32_R_TYPE(rel[i].r_info)) {
111 			case R_386_32:
112 			case R_386_PC32:
113 			case R_386_GOT32:
114 			case R_386_PLT32:
115 			case R_386_RELATIVE:
116 			case R_386_GOTOFF:
117 			case R_386_GOTPC:
118 #ifndef _BOOT_MODE
119 				A = *(uint32 *)(image->text_region.delta + rel[i].r_offset);
120 #else
121 				A = boot_elf32_get_relocation(image->text_region.delta + rel[i].r_offset);
122 #endif
123 				TRACE(("A 0x%08" B_PRIx32 "\n", A));
124 				break;
125 		}
126 		// calc P
127 		switch (ELF32_R_TYPE(rel[i].r_info)) {
128 			case R_386_PC32:
129 			case R_386_GOT32:
130 			case R_386_PLT32:
131 			case R_386_GOTPC:
132 				P = image->text_region.delta + rel[i].r_offset;
133 				TRACE(("P 0x%08" B_PRIx32 "\n", P));
134 				break;
135 		}
136 
137 		switch (ELF32_R_TYPE(rel[i].r_info)) {
138 			case R_386_NONE:
139 				continue;
140 			case R_386_32:
141 				finalAddress = S + A;
142 				break;
143 			case R_386_PC32:
144 				finalAddress = S + A - P;
145 				break;
146 			case R_386_RELATIVE:
147 				// B + A;
148 				finalAddress = image->text_region.delta + A;
149 				break;
150 			case R_386_JMP_SLOT:
151 			case R_386_GLOB_DAT:
152 				finalAddress = S;
153 				break;
154 
155 			default:
156 				dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
157 					ELF32_R_TYPE(rel[i].r_info));
158 				return B_BAD_DATA;
159 		}
160 
161 		resolveAddress = (uint32 *)(addr_t)(image->text_region.delta + rel[i].r_offset);
162 #ifndef _BOOT_MODE
163 		if (!is_in_image(image, (addr_t)resolveAddress)) {
164 			dprintf("arch_elf_relocate_rel: invalid offset 0x%" B_PRIx32 "\n",
165 				rel[i].r_offset);
166 			return B_BAD_ADDRESS;
167 		}
168 		*resolveAddress = finalAddress;
169 #else
170 		boot_elf32_set_relocation((Elf32_Addr)(addr_t)resolveAddress, finalAddress);
171 #endif
172 		TRACE(("-> offset 0x%08" B_PRIx32 "x (0x%08" B_PRIx32 ") = 0x%08" B_PRIx32 "\n",
173 			image->text_region.delta + rel[i].r_offset, rel[i].r_offset, finalAddress));
174 	}
175 
176 	return B_NO_ERROR;
177 }
178 
179 
180 #ifdef _BOOT_MODE
181 status_t
182 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
183 	Elf32_Rela *rel, int relLength)
184 #else
185 int
186 arch_elf_relocate_rela(struct elf_image_info *image,
187 	struct elf_image_info *resolveImage, Elf32_Rela *rel, int relLength)
188 #endif
189 {
190 	dprintf("arch_elf_relocate_rela: not supported on x86\n");
191 	return B_ERROR;
192 }
193 
194 
195 #endif	// !defined(__x86_64__) || defined(ELF32_COMPAT) ||
196 	// (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF32))
197 
198 
199 #if (defined(__x86_64__) && !defined(ELF32_COMPAT)) || \
200 	(defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64))
201 
202 
203 #ifdef _BOOT_MODE
204 status_t
205 boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel,
206 	int relLength)
207 #else
208 int
209 arch_elf_relocate_rel(struct elf_image_info *image,
210 	struct elf_image_info *resolveImage, Elf64_Rel *rel, int relLength)
211 #endif
212 {
213 	dprintf("arch_elf_relocate_rel: not supported on x86_64\n");
214 	return B_ERROR;
215 }
216 
217 
218 #ifdef _BOOT_MODE
219 status_t
220 boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel,
221 	int relLength)
222 #else
223 int
224 arch_elf_relocate_rela(struct elf_image_info *image,
225 	struct elf_image_info *resolveImage, Elf64_Rela *rel, int relLength)
226 #endif
227 {
228 	for (int i = 0; i < relLength / (int)sizeof(Elf64_Rela); i++) {
229 		int type = ELF64_R_TYPE(rel[i].r_info);
230 		int symIndex = ELF64_R_SYM(rel[i].r_info);
231 		Elf64_Addr symAddr = 0;
232 
233 		// Resolve the symbol, if any.
234 		if (symIndex != 0) {
235 			Elf64_Sym* symbol = SYMBOL(image, symIndex);
236 
237 			status_t status;
238 #ifdef _BOOT_MODE
239 			status = boot_elf_resolve_symbol(image, symbol, &symAddr);
240 #else
241 			status = elf_resolve_symbol(image, symbol, resolveImage, &symAddr);
242 #endif
243 			if (status < B_OK)
244 				return status;
245 		}
246 
247 		// Address of the relocation.
248 		Elf64_Addr relocAddr = image->text_region.delta + rel[i].r_offset;
249 
250 		// Calculate the relocation value.
251 		Elf64_Addr relocValue;
252 		switch (type) {
253 			case R_X86_64_NONE:
254 				continue;
255 			case R_X86_64_64:
256 				relocValue = symAddr + rel[i].r_addend;
257 				break;
258 			case R_X86_64_PC32:
259 				relocValue = symAddr + rel[i].r_addend - rel[i].r_offset;
260 				break;
261 			case R_X86_64_GLOB_DAT:
262 			case R_X86_64_JUMP_SLOT:
263 				relocValue = symAddr + rel[i].r_addend;
264 				break;
265 			case R_X86_64_RELATIVE:
266 				relocValue = image->text_region.delta + rel[i].r_addend;
267 				break;
268 			default:
269 				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n",
270 					type);
271 				return B_BAD_DATA;
272 		}
273 #ifdef _BOOT_MODE
274 		boot_elf64_set_relocation(relocAddr, relocValue);
275 #else
276 		if (!is_in_image(image, relocAddr)) {
277 			dprintf("arch_elf_relocate_rela: invalid offset %#lx\n",
278 				rel[i].r_offset);
279 			return B_BAD_ADDRESS;
280 		}
281 
282 		if (type == R_X86_64_PC32)
283 			*(Elf32_Addr *)relocAddr = relocValue;
284 		else
285 			*(Elf64_Addr *)relocAddr = relocValue;
286 #endif
287 	}
288 
289 	return B_OK;
290 }
291 
292 
293 #endif	// (defined(__x86_64__) && !defined(ELF32_COMPAT)) ||
294 	// (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64))
295