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