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