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