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