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