xref: /haiku/src/system/kernel/arch/x86/arch_elf.cpp (revision 9e25244c5e9051f6cd333820d6332397361abd6c)
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) && _BOOT_PLATFORM != efi)
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 	elf_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%lx\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 				TRACE(("S %p (%s)\n", (void *)S, SYMNAME(image, symbol)));
105 			}
106 		}
107 		// calc A
108 		switch (ELF32_R_TYPE(rel[i].r_info)) {
109 			case R_386_32:
110 			case R_386_PC32:
111 			case R_386_GOT32:
112 			case R_386_PLT32:
113 			case R_386_RELATIVE:
114 			case R_386_GOTOFF:
115 			case R_386_GOTPC:
116 #ifndef _BOOT_MODE
117 				A = *(uint32 *)(image->text_region.delta + rel[i].r_offset);
118 #else
119 				A = boot_elf32_get_relocation(image->text_region.delta + rel[i].r_offset);
120 #endif
121 				TRACE(("A %p\n", (void *)A));
122 				break;
123 		}
124 		// calc P
125 		switch (ELF32_R_TYPE(rel[i].r_info)) {
126 			case R_386_PC32:
127 			case R_386_GOT32:
128 			case R_386_PLT32:
129 			case R_386_GOTPC:
130 				P = image->text_region.delta + rel[i].r_offset;
131 				TRACE(("P %p\n", (void *)P));
132 				break;
133 		}
134 
135 		switch (ELF32_R_TYPE(rel[i].r_info)) {
136 			case R_386_NONE:
137 				continue;
138 			case R_386_32:
139 				finalAddress = S + A;
140 				break;
141 			case R_386_PC32:
142 				finalAddress = S + A - P;
143 				break;
144 			case R_386_RELATIVE:
145 				// B + A;
146 				finalAddress = image->text_region.delta + A;
147 				break;
148 			case R_386_JMP_SLOT:
149 			case R_386_GLOB_DAT:
150 				finalAddress = S;
151 				break;
152 
153 			default:
154 				dprintf("arch_elf_relocate_rel: unhandled relocation type %d\n",
155 					ELF32_R_TYPE(rel[i].r_info));
156 				return B_BAD_DATA;
157 		}
158 
159 		resolveAddress = (uint32 *)(image->text_region.delta + rel[i].r_offset);
160 #ifndef _BOOT_MODE
161 		if (!is_in_image(image, (addr_t)resolveAddress)) {
162 			dprintf("arch_elf_relocate_rel: invalid offset %#lx\n",
163 				rel[i].r_offset);
164 			return B_BAD_ADDRESS;
165 		}
166 		*resolveAddress = finalAddress;
167 #else
168 		boot_elf32_set_relocation((Elf32_Addr)resolveAddress, finalAddress);
169 #endif
170 		TRACE(("-> offset %#lx (%#lx) = %#lx\n",
171 			(image->text_region.delta + rel[i].r_offset), rel[i].r_offset, finalAddress));
172 	}
173 
174 	return B_NO_ERROR;
175 }
176 
177 
178 #ifdef _BOOT_MODE
179 status_t
180 boot_arch_elf_relocate_rela(struct preloaded_elf32_image *image,
181 	Elf32_Rela *rel, int relLength)
182 #else
183 int
184 arch_elf_relocate_rela(struct elf_image_info *image,
185 	struct elf_image_info *resolveImage, Elf32_Rela *rel, int relLength)
186 #endif
187 {
188 	dprintf("arch_elf_relocate_rela: not supported on x86\n");
189 	return B_ERROR;
190 }
191 
192 
193 #endif	// !defined(__x86_64__) || defined(ELF32_COMPAT) ||
194 	// (defined(_BOOT_MODE) && _BOOT_PLATFORM != efi)
195 
196 
197 #if (defined(__x86_64__) && !defined(ELF32_COMPAT)) || \
198 	(defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64))
199 
200 
201 #ifdef _BOOT_MODE
202 status_t
203 boot_arch_elf_relocate_rel(preloaded_elf64_image* image, Elf64_Rel* rel,
204 	int relLength)
205 #else
206 int
207 arch_elf_relocate_rel(struct elf_image_info *image,
208 	struct elf_image_info *resolveImage, Elf64_Rel *rel, int relLength)
209 #endif
210 {
211 	dprintf("arch_elf_relocate_rel: not supported on x86_64\n");
212 	return B_ERROR;
213 }
214 
215 
216 #ifdef _BOOT_MODE
217 status_t
218 boot_arch_elf_relocate_rela(preloaded_elf64_image* image, Elf64_Rela* rel,
219 	int relLength)
220 #else
221 int
222 arch_elf_relocate_rela(struct elf_image_info *image,
223 	struct elf_image_info *resolveImage, Elf64_Rela *rel, int relLength)
224 #endif
225 {
226 	for (int i = 0; i < relLength / (int)sizeof(Elf64_Rela); i++) {
227 		int type = ELF64_R_TYPE(rel[i].r_info);
228 		int symIndex = ELF64_R_SYM(rel[i].r_info);
229 		Elf64_Addr symAddr = 0;
230 
231 		// Resolve the symbol, if any.
232 		if (symIndex != 0) {
233 			Elf64_Sym* symbol = SYMBOL(image, symIndex);
234 
235 			status_t status;
236 #ifdef _BOOT_MODE
237 			status = boot_elf_resolve_symbol(image, symbol, &symAddr);
238 #else
239 			status = elf_resolve_symbol(image, symbol, resolveImage, &symAddr);
240 #endif
241 			if (status < B_OK)
242 				return status;
243 		}
244 
245 		// Address of the relocation.
246 		Elf64_Addr relocAddr = image->text_region.delta + rel[i].r_offset;
247 
248 		// Calculate the relocation value.
249 		Elf64_Addr relocValue;
250 		switch (type) {
251 			case R_X86_64_NONE:
252 				continue;
253 			case R_X86_64_64:
254 				relocValue = symAddr + rel[i].r_addend;
255 				break;
256 			case R_X86_64_PC32:
257 				relocValue = symAddr + rel[i].r_addend - rel[i].r_offset;
258 				break;
259 			case R_X86_64_GLOB_DAT:
260 			case R_X86_64_JUMP_SLOT:
261 				relocValue = symAddr + rel[i].r_addend;
262 				break;
263 			case R_X86_64_RELATIVE:
264 				relocValue = image->text_region.delta + rel[i].r_addend;
265 				break;
266 			default:
267 				dprintf("arch_elf_relocate_rela: unhandled relocation type %d\n",
268 					type);
269 				return B_BAD_DATA;
270 		}
271 #ifdef _BOOT_MODE
272 		boot_elf64_set_relocation(relocAddr, relocValue);
273 #else
274 		if (!is_in_image(image, relocAddr)) {
275 			dprintf("arch_elf_relocate_rela: invalid offset %#lx\n",
276 				rel[i].r_offset);
277 			return B_BAD_ADDRESS;
278 		}
279 
280 		if (type == R_X86_64_PC32)
281 			*(Elf32_Addr *)relocAddr = relocValue;
282 		else
283 			*(Elf64_Addr *)relocAddr = relocValue;
284 #endif
285 	}
286 
287 	return B_OK;
288 }
289 
290 
291 #endif	// (defined(__x86_64__) && !defined(ELF32_COMPAT)) ||
292 	// (defined(_BOOT_MODE) && defined(BOOT_SUPPORT_ELF64))
293