xref: /haiku/src/system/boot/loader/elf.cpp (revision 495060760727dd782c9f8a90db71e5d727f19748)
1 /*
2  * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "elf.h"
9 
10 #include <boot/arch.h>
11 #include <boot/platform.h>
12 #include <boot/stage2.h>
13 #include <driver_settings.h>
14 #include <elf_private.h>
15 #include <kernel.h>
16 #include <SupportDefs.h>
17 
18 #include <errno.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <stdlib.h>
22 
23 //#define TRACE_ELF
24 #ifdef TRACE_ELF
25 #	define TRACE(x) dprintf x
26 #else
27 #	define TRACE(x) ;
28 #endif
29 
30 
31 static bool sLoadElfSymbols = true;
32 
33 
34 // #pragma mark - Generic ELF loader
35 
36 
37 template<typename Class>
38 class ELFLoader {
39 private:
40 	typedef typename Class::ImageType	ImageType;
41 	typedef typename Class::RegionType	RegionType;
42 	typedef typename Class::AddrType	AddrType;
43 	typedef typename Class::EhdrType	EhdrType;
44 	typedef typename Class::PhdrType	PhdrType;
45 	typedef typename Class::ShdrType	ShdrType;
46 	typedef typename Class::DynType		DynType;
47 	typedef typename Class::SymType		SymType;
48 	typedef typename Class::RelType		RelType;
49 	typedef typename Class::RelaType	RelaType;
50 
51 public:
52 	static	status_t	Create(int fd, preloaded_image** _image);
53 	static	status_t	Load(int fd, preloaded_image* image);
54 	static	status_t	Relocate(preloaded_image* image);
55 	static	status_t	Resolve(ImageType* image, SymType* symbol,
56 							AddrType* symbolAddress);
57 
58 private:
59 	static	status_t	_LoadSymbolTable(int fd, ImageType* image);
60 	static	status_t	_ParseDynamicSection(ImageType* image);
61 };
62 
63 
64 #ifdef BOOT_SUPPORT_ELF32
65 struct ELF32Class {
66 	static const uint8 kIdentClass = ELFCLASS32;
67 
68 	typedef preloaded_elf32_image	ImageType;
69 	typedef elf32_region			RegionType;
70 	typedef Elf32_Addr				AddrType;
71 	typedef Elf32_Ehdr				EhdrType;
72 	typedef Elf32_Phdr				PhdrType;
73 	typedef Elf32_Shdr				ShdrType;
74 	typedef Elf32_Dyn				DynType;
75 	typedef Elf32_Sym				SymType;
76 	typedef Elf32_Rel				RelType;
77 	typedef Elf32_Rela				RelaType;
78 
79 	static inline status_t
80 	AllocateRegion(AddrType* _address, AddrType size, uint8 protection,
81 		void** _mappedAddress)
82 	{
83 		status_t status = platform_allocate_region((void**)_address, size,
84 			protection, false);
85 		if (status != B_OK)
86 			return status;
87 
88 		*_mappedAddress = (void*)*_address;
89 		return B_OK;
90 	}
91 
92 	static inline void*
93 	Map(AddrType address)
94 	{
95 		return (void*)address;
96 	}
97 };
98 
99 typedef ELFLoader<ELF32Class> ELF32Loader;
100 #endif
101 
102 
103 #ifdef BOOT_SUPPORT_ELF64
104 struct ELF64Class {
105 	static const uint8 kIdentClass = ELFCLASS64;
106 
107 	typedef preloaded_elf64_image	ImageType;
108 	typedef elf64_region			RegionType;
109 	typedef Elf64_Addr				AddrType;
110 	typedef Elf64_Ehdr				EhdrType;
111 	typedef Elf64_Phdr				PhdrType;
112 	typedef Elf64_Shdr				ShdrType;
113 	typedef Elf64_Dyn				DynType;
114 	typedef Elf64_Sym				SymType;
115 	typedef Elf64_Rel				RelType;
116 	typedef Elf64_Rela				RelaType;
117 
118 	static inline status_t
119 	AllocateRegion(AddrType* _address, AddrType size, uint8 protection,
120 		void **_mappedAddress)
121 	{
122 #ifdef _BOOT_PLATFORM_EFI
123 		void* address = (void*)*_address;
124 
125 		status_t status = platform_allocate_region(&address, size, protection,
126 			false);
127 		if (status != B_OK)
128 			return status;
129 
130 		*_mappedAddress = address;
131 		platform_bootloader_address_to_kernel_address(address, _address);
132 #else
133 		// Assume the real 64-bit base address is KERNEL_LOAD_BASE_64_BIT and
134 		// the mappings in the loader address space are at KERNEL_LOAD_BASE.
135 
136 		void* address = (void*)(addr_t)(*_address & 0xffffffff);
137 
138 		status_t status = platform_allocate_region(&address, size, protection,
139 			false);
140 		if (status != B_OK)
141 			return status;
142 
143 		*_mappedAddress = address;
144 		*_address = (AddrType)(addr_t)address + KERNEL_LOAD_BASE_64_BIT
145 			- KERNEL_LOAD_BASE;
146 #endif
147 		return B_OK;
148 	}
149 
150 	static inline void*
151 	Map(AddrType address)
152 	{
153 #ifdef _BOOT_PLATFORM_EFI
154 		void *result;
155 		if (platform_kernel_address_to_bootloader_address(address, &result) != B_OK) {
156 			panic("Couldn't convert address %#lx", address);
157 		}
158 		return result;
159 #else
160 		return (void*)(addr_t)(address - KERNEL_LOAD_BASE_64_BIT
161 			+ KERNEL_LOAD_BASE);
162 #endif
163 	}
164 };
165 
166 typedef ELFLoader<ELF64Class> ELF64Loader;
167 #endif
168 
169 
170 template<typename Class>
171 /*static*/ status_t
172 ELFLoader<Class>::Create(int fd, preloaded_image** _image)
173 {
174 	ImageType* image = (ImageType*)kernel_args_malloc(sizeof(ImageType));
175 	if (image == NULL)
176 		return B_NO_MEMORY;
177 
178 	ssize_t length = read_pos(fd, 0, &image->elf_header, sizeof(EhdrType));
179 	if (length < (ssize_t)sizeof(EhdrType)) {
180 		kernel_args_free(image);
181 		return B_BAD_TYPE;
182 	}
183 
184 	const EhdrType& elfHeader = image->elf_header;
185 
186 	if (memcmp(elfHeader.e_ident, ELFMAG, 4) != 0
187 		|| elfHeader.e_ident[4] != Class::kIdentClass
188 		|| elfHeader.e_phoff == 0
189 		|| !elfHeader.IsHostEndian()
190 		|| elfHeader.e_phentsize != sizeof(PhdrType)) {
191 		kernel_args_free(image);
192 		return B_BAD_TYPE;
193 	}
194 
195 	image->elf_class = elfHeader.e_ident[EI_CLASS];
196 
197 	*_image = image;
198 	return B_OK;
199 }
200 
201 
202 template<typename Class>
203 /*static*/ status_t
204 ELFLoader<Class>::Load(int fd, preloaded_image* _image)
205 {
206 	size_t totalSize;
207 	ssize_t length;
208 	status_t status;
209 	void* mappedRegion = NULL;
210 
211 	ImageType* image = static_cast<ImageType*>(_image);
212 	const EhdrType& elfHeader = image->elf_header;
213 
214 	ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize;
215 	PhdrType* programHeaders = (PhdrType*)malloc(size);
216 	if (programHeaders == NULL) {
217 		dprintf("error allocating space for program headers\n");
218 		status = B_NO_MEMORY;
219 		goto error1;
220 	}
221 
222 	length = read_pos(fd, elfHeader.e_phoff, programHeaders, size);
223 	if (length < size) {
224 		TRACE(("error reading in program headers\n"));
225 		status = B_ERROR;
226 		goto error1;
227 	}
228 
229 	// create an area large enough to hold the image
230 
231 	image->data_region.size = 0;
232 	image->text_region.size = 0;
233 
234 	for (int32 i = 0; i < elfHeader.e_phnum; i++) {
235 		PhdrType& header = programHeaders[i];
236 
237 		switch (header.p_type) {
238 			case PT_LOAD:
239 				break;
240 			case PT_DYNAMIC:
241 				image->dynamic_section.start = header.p_vaddr;
242 				image->dynamic_section.size = header.p_memsz;
243 				continue;
244 			case PT_INTERP:
245 			case PT_PHDR:
246 			case PT_ARM_UNWIND:
247 				// known but unused type
248 				continue;
249 			default:
250 				dprintf("unhandled pheader type 0x%" B_PRIx32 "\n", header.p_type);
251 				continue;
252 		}
253 
254 		RegionType* region;
255 		if (header.IsReadWrite()) {
256 			if (image->data_region.size != 0) {
257 				dprintf("elf: rw already handled!\n");
258 				continue;
259 			}
260 			region = &image->data_region;
261 		} else if (header.IsExecutable()) {
262 			if (image->text_region.size != 0) {
263 				dprintf("elf: ro already handled!\n");
264 				continue;
265 			}
266 			region = &image->text_region;
267 		} else
268 			continue;
269 
270 		region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE);
271 		region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE),
272 			B_PAGE_SIZE);
273 		region->delta = -region->start;
274 
275 		TRACE(("segment %ld: start = 0x%llx, size = %llu, delta = %llx\n", i,
276 			(uint64)region->start, (uint64)region->size,
277 			(int64)(AddrType)region->delta));
278 	}
279 
280 	// found both, text and data?
281 	if (image->data_region.size == 0 || image->text_region.size == 0) {
282 		dprintf("Couldn't find both text and data segment!\n");
283 		status = B_BAD_DATA;
284 		goto error1;
285 	}
286 
287 	// get the segment order
288 	RegionType* firstRegion;
289 	RegionType* secondRegion;
290 	if (image->text_region.start < image->data_region.start) {
291 		firstRegion = &image->text_region;
292 		secondRegion = &image->data_region;
293 	} else {
294 		firstRegion = &image->data_region;
295 		secondRegion = &image->text_region;
296 	}
297 
298 	// The kernel and the modules are relocatable, thus AllocateRegion()
299 	// can automatically allocate an address, but shall prefer the specified
300 	// base address.
301 	totalSize = secondRegion->start + secondRegion->size - firstRegion->start;
302 	if (Class::AllocateRegion(&firstRegion->start, totalSize,
303 			B_READ_AREA | B_WRITE_AREA, &mappedRegion) != B_OK) {
304 		status = B_NO_MEMORY;
305 		goto error1;
306 	}
307 
308 	// initialize the region pointers to the allocated region
309 	secondRegion->start += firstRegion->start + firstRegion->delta;
310 
311 	image->data_region.delta += image->data_region.start;
312 	image->text_region.delta += image->text_region.start;
313 
314 	TRACE(("text: start 0x%llx, size 0x%llx, delta 0x%llx\n",
315 		(uint64)image->text_region.start, (uint64)image->text_region.size,
316 		(int64)(AddrType)image->text_region.delta));
317 	TRACE(("data: start 0x%llx, size 0x%llx, delta 0x%llx\n",
318 		(uint64)image->data_region.start, (uint64)image->data_region.size,
319 		(int64)(AddrType)image->data_region.delta));
320 
321 	// load program data
322 
323 	for (int32 i = 0; i < elfHeader.e_phnum; i++) {
324 		PhdrType& header = programHeaders[i];
325 
326 		if (header.p_type != PT_LOAD)
327 			continue;
328 
329 		RegionType* region;
330 		if (header.IsReadWrite())
331 			region = &image->data_region;
332 		else if (header.IsExecutable())
333 			region = &image->text_region;
334 		else
335 			continue;
336 
337 		TRACE(("load segment %ld (%llu bytes) mapped at %p...\n", i,
338 			(uint64)header.p_filesz, Class::Map(region->start)));
339 
340 		length = read_pos(fd, header.p_offset,
341 			Class::Map(region->start + (header.p_vaddr % B_PAGE_SIZE)),
342 			header.p_filesz);
343 		if (length < (ssize_t)header.p_filesz) {
344 			status = B_BAD_DATA;
345 			dprintf("error reading in seg %" B_PRId32 "\n", i);
346 			goto error2;
347 		}
348 
349 		// Clear anything above the file size (that may also contain the BSS
350 		// area)
351 
352 		uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz;
353 		if (offset < region->size)
354 			memset(Class::Map(region->start + offset), 0, region->size - offset);
355 	}
356 
357 	// offset dynamic section, and program entry addresses by the delta of the
358 	// regions
359 	image->dynamic_section.start += image->text_region.delta;
360 	image->elf_header.e_entry += image->text_region.delta;
361 
362 	image->num_debug_symbols = 0;
363 	image->debug_symbols = NULL;
364 	image->debug_string_table = NULL;
365 
366 	if (sLoadElfSymbols)
367 		_LoadSymbolTable(fd, image);
368 
369 	free(programHeaders);
370 
371 	return B_OK;
372 
373 error2:
374 	if (mappedRegion != NULL)
375 		platform_free_region(mappedRegion, totalSize);
376 error1:
377 	free(programHeaders);
378 	kernel_args_free(image);
379 
380 	return status;
381 }
382 
383 
384 template<typename Class>
385 /*static*/ status_t
386 ELFLoader<Class>::Relocate(preloaded_image* _image)
387 {
388 	ImageType* image = static_cast<ImageType*>(_image);
389 
390 	status_t status = _ParseDynamicSection(image);
391 	if (status != B_OK)
392 		return status;
393 
394 	// deal with the rels first
395 	if (image->rel) {
396 		TRACE(("total %i relocs\n",
397 			(int)image->rel_len / (int)sizeof(RelType)));
398 
399 		status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len);
400 		if (status != B_OK)
401 			return status;
402 	}
403 
404 	if (image->pltrel) {
405 		RelType* pltrel = image->pltrel;
406 		if (image->pltrel_type == DT_REL) {
407 			TRACE(("total %i plt-relocs\n",
408 				(int)image->pltrel_len / (int)sizeof(RelType)));
409 
410 			status = boot_arch_elf_relocate_rel(image, pltrel,
411 				image->pltrel_len);
412 		} else {
413 			TRACE(("total %i plt-relocs\n",
414 				(int)image->pltrel_len / (int)sizeof(RelaType)));
415 
416 			status = boot_arch_elf_relocate_rela(image, (RelaType*)pltrel,
417 				image->pltrel_len);
418 		}
419 		if (status != B_OK)
420 			return status;
421 	}
422 
423 	if (image->rela) {
424 		TRACE(("total %i rela relocs\n",
425 			(int)image->rela_len / (int)sizeof(RelaType)));
426 		status = boot_arch_elf_relocate_rela(image, image->rela,
427 			image->rela_len);
428 		if (status != B_OK)
429 			return status;
430 	}
431 
432 	return B_OK;
433 }
434 
435 template<typename Class>
436 /*static*/ status_t
437 ELFLoader<Class>::Resolve(ImageType* image, SymType* symbol,
438 	AddrType* symbolAddress)
439 {
440 	switch (symbol->st_shndx) {
441 		case SHN_UNDEF:
442 			// Since we do that only for the kernel, there shouldn't be
443 			// undefined symbols.
444 			TRACE(("elf_resolve_symbol: undefined symbol\n"));
445 			return B_MISSING_SYMBOL;
446 		case SHN_ABS:
447 			*symbolAddress = symbol->st_value;
448 			return B_NO_ERROR;
449 		case SHN_COMMON:
450 			// ToDo: finish this
451 			TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n"));
452 			return B_ERROR;
453 		default:
454 			// standard symbol
455 			*symbolAddress = symbol->st_value + image->text_region.delta;
456 			return B_OK;
457 	}
458 }
459 
460 
461 template<typename Class>
462 /*static*/ status_t
463 ELFLoader<Class>::_LoadSymbolTable(int fd, ImageType* image)
464 {
465 	const EhdrType& elfHeader = image->elf_header;
466 	SymType* symbolTable = NULL;
467 	ShdrType* stringHeader = NULL;
468 	uint32 numSymbols = 0;
469 	char* stringTable;
470 	status_t status;
471 
472 	// get section headers
473 
474 	ssize_t size = elfHeader.e_shnum * elfHeader.e_shentsize;
475 	ShdrType* sectionHeaders = (ShdrType*)malloc(size);
476 	if (sectionHeaders == NULL) {
477 		dprintf("error allocating space for section headers\n");
478 		return B_NO_MEMORY;
479 	}
480 
481 	ssize_t length = read_pos(fd, elfHeader.e_shoff, sectionHeaders, size);
482 	if (length < size) {
483 		TRACE(("error reading in program headers\n"));
484 		status = B_ERROR;
485 		goto error1;
486 	}
487 
488 	// find symbol table in section headers
489 
490 	for (int32 i = 0; i < elfHeader.e_shnum; i++) {
491 		if (sectionHeaders[i].sh_type == SHT_SYMTAB) {
492 			stringHeader = &sectionHeaders[sectionHeaders[i].sh_link];
493 
494 			if (stringHeader->sh_type != SHT_STRTAB) {
495 				TRACE(("doesn't link to string table\n"));
496 				status = B_BAD_DATA;
497 				goto error1;
498 			}
499 
500 			// read in symbol table
501 			size = sectionHeaders[i].sh_size;
502 			symbolTable = (SymType*)kernel_args_malloc(size);
503 			if (symbolTable == NULL) {
504 				status = B_NO_MEMORY;
505 				goto error1;
506 			}
507 
508 			length = read_pos(fd, sectionHeaders[i].sh_offset, symbolTable,
509 				size);
510 			if (length < size) {
511 				TRACE(("error reading in symbol table\n"));
512 				status = B_ERROR;
513 				goto error1;
514 			}
515 
516 			numSymbols = size / sizeof(SymType);
517 			break;
518 		}
519 	}
520 
521 	if (symbolTable == NULL) {
522 		TRACE(("no symbol table\n"));
523 		status = B_BAD_VALUE;
524 		goto error1;
525 	}
526 
527 	// read in string table
528 
529 	size = stringHeader->sh_size;
530 	stringTable = (char*)kernel_args_malloc(size);
531 	if (stringTable == NULL) {
532 		status = B_NO_MEMORY;
533 		goto error2;
534 	}
535 
536 	length = read_pos(fd, stringHeader->sh_offset, stringTable, size);
537 	if (length < size) {
538 		TRACE(("error reading in string table\n"));
539 		status = B_ERROR;
540 		goto error3;
541 	}
542 
543 	TRACE(("loaded %ld debug symbols\n", numSymbols));
544 
545 	// insert tables into image
546 	image->debug_symbols = symbolTable;
547 	image->num_debug_symbols = numSymbols;
548 	image->debug_string_table = stringTable;
549 	image->debug_string_table_size = size;
550 
551 	free(sectionHeaders);
552 	return B_OK;
553 
554 error3:
555 	kernel_args_free(stringTable);
556 error2:
557 	kernel_args_free(symbolTable);
558 error1:
559 	free(sectionHeaders);
560 
561 	return status;
562 }
563 
564 
565 template<typename Class>
566 /*static*/ status_t
567 ELFLoader<Class>::_ParseDynamicSection(ImageType* image)
568 {
569 	image->syms = 0;
570 	image->rel = 0;
571 	image->rel_len = 0;
572 	image->rela = 0;
573 	image->rela_len = 0;
574 	image->pltrel = 0;
575 	image->pltrel_len = 0;
576 	image->pltrel_type = 0;
577 
578 	if(image->dynamic_section.start == 0)
579 		return B_ERROR;
580 
581 	DynType* d = (DynType*)Class::Map(image->dynamic_section.start);
582 
583 	for (int i = 0; d[i].d_tag != DT_NULL; i++) {
584 		switch (d[i].d_tag) {
585 			case DT_HASH:
586 			case DT_STRTAB:
587 				break;
588 			case DT_SYMTAB:
589 				image->syms = (SymType*)Class::Map(d[i].d_un.d_ptr
590 					+ image->text_region.delta);
591 				break;
592 			case DT_REL:
593 				image->rel = (RelType*)Class::Map(d[i].d_un.d_ptr
594 					+ image->text_region.delta);
595 				break;
596 			case DT_RELSZ:
597 				image->rel_len = d[i].d_un.d_val;
598 				break;
599 			case DT_RELA:
600 				image->rela = (RelaType*)Class::Map(d[i].d_un.d_ptr
601 					+ image->text_region.delta);
602 				break;
603 			case DT_RELASZ:
604 				image->rela_len = d[i].d_un.d_val;
605 				break;
606 			case DT_JMPREL:
607 				image->pltrel = (RelType*)Class::Map(d[i].d_un.d_ptr
608 					+ image->text_region.delta);
609 				break;
610 			case DT_PLTRELSZ:
611 				image->pltrel_len = d[i].d_un.d_val;
612 				break;
613 			case DT_PLTREL:
614 				image->pltrel_type = d[i].d_un.d_val;
615 				break;
616 
617 			default:
618 				continue;
619 		}
620 	}
621 
622 	// lets make sure we found all the required sections
623 	if (image->syms == NULL)
624 		return B_ERROR;
625 
626 	return B_OK;
627 }
628 
629 
630 // #pragma mark -
631 
632 
633 void
634 elf_init()
635 {
636 	void* settings = load_driver_settings("kernel");
637 	if (settings == NULL)
638 		return;
639 
640 	sLoadElfSymbols = get_driver_boolean_parameter(settings, "load_symbols",
641 		false, false);
642 
643 	unload_driver_settings(settings);
644 }
645 
646 
647 status_t
648 elf_load_image(int fd, preloaded_image** _image)
649 {
650 	status_t status = B_ERROR;
651 
652 	TRACE(("elf_load_image(fd = %d, _image = %p)\n", fd, _image));
653 
654 #if BOOT_SUPPORT_ELF64
655 	if (gKernelArgs.kernel_image == NULL
656 		|| gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
657 		status = ELF64Loader::Create(fd, _image);
658 		if (status == B_OK)
659 			return ELF64Loader::Load(fd, *_image);
660 		else if (status != B_BAD_TYPE)
661 			return status;
662 	}
663 #endif
664 #if BOOT_SUPPORT_ELF32
665 	if (gKernelArgs.kernel_image == NULL
666 		|| gKernelArgs.kernel_image->elf_class == ELFCLASS32) {
667 		status = ELF32Loader::Create(fd, _image);
668 		if (status == B_OK)
669 			return ELF32Loader::Load(fd, *_image);
670 	}
671 #endif
672 
673 	return status;
674 }
675 
676 
677 status_t
678 elf_load_image(Directory* directory, const char* path)
679 {
680 	preloaded_image* image;
681 
682 	TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path));
683 
684 	int fd = open_from(directory, path, O_RDONLY);
685 	if (fd < 0)
686 		return fd;
687 
688 	// check if this file has already been loaded
689 
690 	struct stat stat;
691 	if (fstat(fd, &stat) < 0)
692 		return errno;
693 
694 	image = gKernelArgs.preloaded_images;
695 	for (; image != NULL; image = image->next) {
696 		if (image->inode == stat.st_ino) {
697 			// file has already been loaded, no need to load it twice!
698 			close(fd);
699 			return B_OK;
700 		}
701 	}
702 
703 	// we still need to load it, so do it
704 
705 	status_t status = elf_load_image(fd, &image);
706 	if (status == B_OK) {
707 		image->name = kernel_args_strdup(path);
708 		image->inode = stat.st_ino;
709 
710 		// insert to kernel args
711 		image->next = gKernelArgs.preloaded_images;
712 		gKernelArgs.preloaded_images = image;
713 	} else
714 		kernel_args_free(image);
715 
716 	close(fd);
717 	return status;
718 }
719 
720 
721 status_t
722 elf_relocate_image(preloaded_image* image)
723 {
724 #ifdef BOOT_SUPPORT_ELF64
725 	if (image->elf_class == ELFCLASS64)
726 		return ELF64Loader::Relocate(image);
727 	else
728 #endif
729 #ifdef BOOT_SUPPORT_ELF32
730 		return ELF32Loader::Relocate(image);
731 #else
732 		return B_ERROR;
733 #endif
734 }
735 
736 
737 #ifdef BOOT_SUPPORT_ELF32
738 status_t
739 boot_elf_resolve_symbol(preloaded_elf32_image* image, Elf32_Sym* symbol,
740 	Elf32_Addr* symbolAddress)
741 {
742 	return ELF32Loader::Resolve(image, symbol, symbolAddress);
743 }
744 #endif
745 
746 
747 #ifdef BOOT_SUPPORT_ELF64
748 status_t
749 boot_elf_resolve_symbol(preloaded_elf64_image* image, Elf64_Sym* symbol,
750 	Elf64_Addr* symbolAddress)
751 {
752 	return ELF64Loader::Resolve(image, symbol, symbolAddress);
753 }
754 
755 void
756 boot_elf64_set_relocation(Elf64_Addr resolveAddress, Elf64_Addr finalAddress)
757 {
758 	Elf64_Addr* dest = (Elf64_Addr*)ELF64Class::Map(resolveAddress);
759 	*dest = finalAddress;
760 }
761 #endif
762