xref: /haiku/src/system/boot/loader/elf.cpp (revision 323b65468e5836bb27a5e373b14027d902349437)
1 /*
2  * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "elf.h"
8 
9 #include <boot/arch.h>
10 #include <boot/platform.h>
11 #include <boot/stage2.h>
12 #include <driver_settings.h>
13 #include <elf32.h>
14 #include <kernel.h>
15 
16 #include <errno.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <stdlib.h>
20 
21 //#define TRACE_ELF
22 #ifdef TRACE_ELF
23 #	define TRACE(x) dprintf x
24 #else
25 #	define TRACE(x) ;
26 #endif
27 
28 
29 static bool sLoadElfSymbols = true;
30 
31 
32 void
33 elf_init()
34 {
35 // TODO: This cannot work, since the driver settings are loaded *after* the
36 // kernel has been loaded successfully.
37 #if 0
38 	void *settings = load_driver_settings("kernel");
39 	if (settings == NULL)
40 		return;
41 
42 	sLoadElfSymbols = !get_driver_boolean_parameter(settings, "load_symbols",
43 		false, false);
44 	unload_driver_settings(settings);
45 #endif
46 }
47 
48 
49 static status_t
50 verify_elf_header(struct Elf32_Ehdr &header)
51 {
52 	if (memcmp(header.e_ident, ELF_MAGIC, 4) != 0
53 		|| header.e_ident[4] != ELFCLASS32
54 		|| header.e_phoff == 0
55 		|| !header.IsHostEndian()
56 		|| header.e_phentsize != sizeof(struct Elf32_Phdr))
57 		return B_BAD_TYPE;
58 
59 	return B_OK;
60 }
61 
62 
63 static status_t
64 elf_parse_dynamic_section(struct preloaded_image *image)
65 {
66 	image->syms = 0;
67 	image->rel = 0;
68 	image->rel_len = 0;
69 	image->rela = 0;
70 	image->rela_len = 0;
71 	image->pltrel = 0;
72 	image->pltrel_len = 0;
73 	image->pltrel_type = 0;
74 
75 	struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_section.start;
76 	if (!d)
77 		return B_ERROR;
78 
79 	for (int i = 0; d[i].d_tag != DT_NULL; i++) {
80 		switch (d[i].d_tag) {
81 			case DT_HASH:
82 			case DT_STRTAB:
83 				break;
84 			case DT_SYMTAB:
85 				image->syms = (struct Elf32_Sym *)(d[i].d_un.d_ptr
86 					+ image->text_region.delta);
87 				break;
88 			case DT_REL:
89 				image->rel = (struct Elf32_Rel *)(d[i].d_un.d_ptr
90 					+ image->text_region.delta);
91 				break;
92 			case DT_RELSZ:
93 				image->rel_len = d[i].d_un.d_val;
94 				break;
95 			case DT_RELA:
96 				image->rela = (struct Elf32_Rela *)(d[i].d_un.d_ptr
97 					+ image->text_region.delta);
98 				break;
99 			case DT_RELASZ:
100 				image->rela_len = d[i].d_un.d_val;
101 				break;
102 			case DT_JMPREL:
103 				image->pltrel = (struct Elf32_Rel *)(d[i].d_un.d_ptr
104 					+ image->text_region.delta);
105 				break;
106 			case DT_PLTRELSZ:
107 				image->pltrel_len = d[i].d_un.d_val;
108 				break;
109 			case DT_PLTREL:
110 				image->pltrel_type = d[i].d_un.d_val;
111 				break;
112 
113 			default:
114 				continue;
115 		}
116 	}
117 
118 	// lets make sure we found all the required sections
119 	if (image->syms == NULL)
120 		return B_ERROR;
121 
122 	return B_OK;
123 }
124 
125 
126 static status_t
127 load_elf_symbol_table(int fd, preloaded_image *image)
128 {
129 	struct Elf32_Ehdr &elfHeader = image->elf_header;
130 	Elf32_Sym *symbolTable = NULL;
131 	Elf32_Shdr *stringHeader = NULL;
132 	uint32 numSymbols = 0;
133 	char *stringTable;
134 	status_t status;
135 
136 	// get section headers
137 
138 	ssize_t size = elfHeader.e_shnum * elfHeader.e_shentsize;
139 	Elf32_Shdr *sectionHeaders = (struct Elf32_Shdr *)malloc(size);
140 	if (sectionHeaders == NULL) {
141 		dprintf("error allocating space for section headers\n");
142 		return B_NO_MEMORY;
143 	}
144 
145 	ssize_t length = read_pos(fd, elfHeader.e_shoff, sectionHeaders, size);
146 	if (length < size) {
147 		TRACE(("error reading in program headers\n"));
148 		status = B_ERROR;
149 		goto error1;
150 	}
151 
152 	// find symbol table in section headers
153 
154 	for (int32 i = 0; i < elfHeader.e_shnum; i++) {
155 		if (sectionHeaders[i].sh_type == SHT_SYMTAB) {
156 			stringHeader = &sectionHeaders[sectionHeaders[i].sh_link];
157 
158 			if (stringHeader->sh_type != SHT_STRTAB) {
159 				TRACE(("doesn't link to string table\n"));
160 				status = B_BAD_DATA;
161 				goto error1;
162 			}
163 
164 			// read in symbol table
165 			symbolTable = (Elf32_Sym *)kernel_args_malloc(
166 				size = sectionHeaders[i].sh_size);
167 			if (symbolTable == NULL) {
168 				status = B_NO_MEMORY;
169 				goto error1;
170 			}
171 
172 			length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable,
173 				size);
174 			if (length < size) {
175 				TRACE(("error reading in symbol table\n"));
176 				status = B_ERROR;
177 				goto error1;
178 			}
179 
180 			numSymbols = size / sizeof(Elf32_Sym);
181 			break;
182 		}
183 	}
184 
185 	if (symbolTable == NULL) {
186 		TRACE(("no symbol table\n"));
187 		status = B_BAD_VALUE;
188 		goto error1;
189 	}
190 
191 	// read in string table
192 
193 	stringTable = (char *)kernel_args_malloc(size = stringHeader->sh_size);
194 	if (stringTable == NULL) {
195 		status = B_NO_MEMORY;
196 		goto error2;
197 	}
198 
199 	length = read_pos(fd, stringHeader->sh_offset, stringTable, size);
200 	if (length < size) {
201 		TRACE(("error reading in string table\n"));
202 		status = B_ERROR;
203 		goto error3;
204 	}
205 
206 	TRACE(("loaded %ld debug symbols\n", numSymbols));
207 
208 	// insert tables into image
209 	image->debug_symbols = symbolTable;
210 	image->num_debug_symbols = numSymbols;
211 	image->debug_string_table = stringTable;
212 	image->debug_string_table_size = size;
213 
214 	free(sectionHeaders);
215 	return B_OK;
216 
217 error3:
218 	kernel_args_free(stringTable);
219 error2:
220 	kernel_args_free(symbolTable);
221 error1:
222 	free(sectionHeaders);
223 
224 	return status;
225 }
226 
227 
228 status_t
229 elf_load_image(int fd, preloaded_image *image)
230 {
231 	size_t totalSize;
232 	status_t status;
233 
234 	TRACE(("elf_load_image(fd = %d, image = %p)\n", fd, image));
235 
236 	struct Elf32_Ehdr &elfHeader = image->elf_header;
237 
238 	ssize_t length = read_pos(fd, 0, &elfHeader, sizeof(Elf32_Ehdr));
239 	if (length < (ssize_t)sizeof(Elf32_Ehdr))
240 		return B_BAD_TYPE;
241 
242 	status = verify_elf_header(elfHeader);
243 	if (status < B_OK)
244 		return status;
245 
246 	ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize;
247 	Elf32_Phdr *programHeaders = (struct Elf32_Phdr *)malloc(size);
248 	if (programHeaders == NULL) {
249 		dprintf("error allocating space for program headers\n");
250 		return B_NO_MEMORY;
251 	}
252 
253 	length = read_pos(fd, elfHeader.e_phoff, programHeaders, size);
254 	if (length < size) {
255 		TRACE(("error reading in program headers\n"));
256 		status = B_ERROR;
257 		goto error1;
258 	}
259 
260 	// create an area large enough to hold the image
261 
262 	image->data_region.size = 0;
263 	image->text_region.size = 0;
264 
265 	for (int32 i = 0; i < elfHeader.e_phnum; i++) {
266 		Elf32_Phdr &header = programHeaders[i];
267 
268 		switch (header.p_type) {
269 			case PT_LOAD:
270 				break;
271 			case PT_DYNAMIC:
272 				image->dynamic_section.start = header.p_vaddr;
273 				image->dynamic_section.size = header.p_memsz;
274 				continue;
275 			case PT_INTERP:
276 			case PT_PHDR:
277 				// known but unused type
278 				continue;
279 			default:
280 				dprintf("unhandled pheader type 0x%lx\n", header.p_type);
281 				continue;
282 		}
283 
284 		elf_region *region;
285 		if (header.IsReadWrite()) {
286 			if (image->data_region.size != 0) {
287 				dprintf("elf: rw already handled!\n");
288 				continue;
289 			}
290 			region = &image->data_region;
291 		} else if (header.IsExecutable()) {
292 			if (image->text_region.size != 0) {
293 				dprintf("elf: ro already handled!\n");
294 				continue;
295 			}
296 			region = &image->text_region;
297 		} else
298 			continue;
299 
300 		region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE);
301 		region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE),
302 			B_PAGE_SIZE);
303 		region->delta = -region->start;
304 
305 		TRACE(("segment %d: start = %p, size = %lu, delta = %lx\n", i,
306 			region->start, region->size, region->delta));
307 	}
308 
309 	// found both, text and data?
310 	if (image->data_region.size == 0 || image->text_region.size == 0) {
311 		dprintf("Couldn't find both text and data segment!\n");
312 		status = B_BAD_DATA;
313 		goto error1;
314 	}
315 
316 	// get the segment order
317 	elf_region *firstRegion;
318 	elf_region *secondRegion;
319 	if (image->text_region.start < image->data_region.start) {
320 		firstRegion = &image->text_region;
321 		secondRegion = &image->data_region;
322 	} else {
323 		firstRegion = &image->data_region;
324 		secondRegion = &image->text_region;
325 	}
326 
327 	// Check whether the segments have an unreasonable amount of unused space
328 	// inbetween.
329 	totalSize = secondRegion->start + secondRegion->size - firstRegion->start;
330 	if (totalSize > image->text_region.size + image->data_region.size
331 		+ 8 * 1024) {
332 		status = B_BAD_DATA;
333 		goto error1;
334 	}
335 
336 	// The kernel and the modules are relocatable, thus
337 	// platform_allocate_region() can automatically allocate an address,
338 	// but shall prefer the specified base address.
339 	if (platform_allocate_region((void **)&firstRegion->start, totalSize,
340 			B_READ_AREA | B_WRITE_AREA, false) < B_OK) {
341 		status = B_NO_MEMORY;
342 		goto error1;
343 	}
344 
345 	// initialize the region pointers to the allocated region
346 	secondRegion->start += firstRegion->start + firstRegion->delta;
347 
348 	image->data_region.delta += image->data_region.start;
349 	image->text_region.delta += image->text_region.start;
350 
351 	// load program data
352 
353 	for (int i = 0; i < elfHeader.e_phnum; i++) {
354 		Elf32_Phdr &header = programHeaders[i];
355 
356 		if (header.p_type != PT_LOAD)
357 			continue;
358 
359 		elf_region *region;
360 		if (header.IsReadWrite())
361 			region = &image->data_region;
362 		else if (header.IsExecutable())
363 			region = &image->text_region;
364 		else
365 			continue;
366 
367 		TRACE(("load segment %d (%ld bytes)...\n", i, header.p_filesz));
368 
369 		length = read_pos(fd, header.p_offset,
370 			(void *)(region->start + (header.p_vaddr % B_PAGE_SIZE)),
371 			header.p_filesz);
372 		if (length < (ssize_t)header.p_filesz) {
373 			status = B_BAD_DATA;
374 			dprintf("error reading in seg %d\n", i);
375 			goto error2;
376 		}
377 
378 		// Clear anything above the file size (that may also contain the BSS
379 		// area)
380 
381 		uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz;
382 		if (offset < region->size)
383 			memset((void *)(region->start + offset), 0, region->size - offset);
384 	}
385 
386 	// offset dynamic section, and program entry addresses by the delta of the
387 	// regions
388 	image->dynamic_section.start += image->text_region.delta;
389 	image->elf_header.e_entry += image->text_region.delta;
390 
391 	image->num_debug_symbols = 0;
392 	image->debug_symbols = NULL;
393 	image->debug_string_table = NULL;
394 
395 	if (sLoadElfSymbols)
396 		load_elf_symbol_table(fd, image);
397 
398 	free(programHeaders);
399 
400 	return B_OK;
401 
402 error2:
403 	if (image->text_region.start != 0)
404 		platform_free_region((void *)image->text_region.start, totalSize);
405 error1:
406 	free(programHeaders);
407 
408 	return status;
409 }
410 
411 
412 status_t
413 elf_load_image(Directory *directory, const char *path)
414 {
415 	preloaded_image *image;
416 
417 	TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path));
418 
419 	int fd = open_from(directory, path, O_RDONLY);
420 	if (fd < 0)
421 		return fd;
422 
423 	// check if this file has already been loaded
424 
425 	struct stat stat;
426 	if (fstat(fd, &stat) < 0)
427 		return errno;
428 
429 	image = gKernelArgs.preloaded_images;
430 	for (; image != NULL; image = image->next) {
431 		if (image->inode == stat.st_ino) {
432 			// file has already been loaded, no need to load it twice!
433 			close(fd);
434 			return B_OK;
435 		}
436 	}
437 
438 	// we still need to load it, so do it
439 
440 	image = (preloaded_image *)kernel_args_malloc(sizeof(preloaded_image));
441 	if (image == NULL) {
442 		close(fd);
443 		return B_NO_MEMORY;
444 	}
445 
446 	status_t status = elf_load_image(fd, image);
447 	if (status == B_OK) {
448 		image->name = kernel_args_strdup(path);
449 		image->inode = stat.st_ino;
450 
451 		// insert to kernel args
452 		image->next = gKernelArgs.preloaded_images;
453 		gKernelArgs.preloaded_images = image;
454 	} else
455 		kernel_args_free(image);
456 
457 	close(fd);
458 	return status;
459 }
460 
461 
462 status_t
463 elf_relocate_image(struct preloaded_image *image)
464 {
465 	status_t status = elf_parse_dynamic_section(image);
466 	if (status != B_OK)
467 		return status;
468 
469 	// deal with the rels first
470 	if (image->rel) {
471 		TRACE(("total %i relocs\n",
472 			image->rel_len / (int)sizeof(struct Elf32_Rel)));
473 
474 		status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len);
475 		if (status < B_OK)
476 			return status;
477 	}
478 
479 	if (image->pltrel) {
480 		TRACE(("total %i plt-relocs\n",
481 			image->pltrel_len / (int)sizeof(struct Elf32_Rel)));
482 
483 		if (image->pltrel_type == DT_REL) {
484 			status = boot_arch_elf_relocate_rel(image, image->pltrel,
485 				image->pltrel_len);
486 		} else {
487 			status = boot_arch_elf_relocate_rela(image,
488 				(struct Elf32_Rela *)image->pltrel, image->pltrel_len);
489 		}
490 		if (status < B_OK)
491 			return status;
492 	}
493 
494 	if (image->rela) {
495 		TRACE(("total %i rela relocs\n",
496 			image->rela_len / (int)sizeof(struct Elf32_Rela)));
497 		status = boot_arch_elf_relocate_rela(image, image->rela,
498 			image->rela_len);
499 		if (status < B_OK)
500 			return status;
501 	}
502 
503 	return B_OK;
504 }
505 
506 
507 status_t
508 boot_elf_resolve_symbol(struct preloaded_image *image,
509 	struct Elf32_Sym *symbol, addr_t *symbolAddress)
510 {
511 	switch (symbol->st_shndx) {
512 		case SHN_UNDEF:
513 			// Since we do that only for the kernel, there shouldn't be
514 			// undefined symbols.
515 			return B_MISSING_SYMBOL;
516 		case SHN_ABS:
517 			*symbolAddress = symbol->st_value;
518 			return B_NO_ERROR;
519 		case SHN_COMMON:
520 			// ToDo: finish this
521 			TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n"));
522 			return B_ERROR;
523 		default:
524 			// standard symbol
525 			*symbolAddress = symbol->st_value + image->text_region.delta;
526 			return B_NO_ERROR;
527 	}
528 }
529