headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / boot / loader / elf.cpp
blob950a0423741231cb5f98c63b8272f10c83305987
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 */
8 #include "elf.h"
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>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <stdlib.h>
23 //#define TRACE_ELF
24 #ifdef TRACE_ELF
25 # define TRACE(x) dprintf x
26 #else
27 # define TRACE(x) ;
28 #endif
31 static bool sLoadElfSymbols = true;
34 // #pragma mark - Generic ELF loader
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;
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);
58 private:
59 static status_t _LoadSymbolTable(int fd, ImageType* image);
60 static status_t _ParseDynamicSection(ImageType* image);
64 #ifdef BOOT_SUPPORT_ELF32
65 struct ELF32Class {
66 static const uint8 kIdentClass = ELFCLASS32;
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;
79 static inline status_t
80 AllocateRegion(AddrType* _address, AddrType size, uint8 protection,
81 void** _mappedAddress)
83 status_t status = platform_allocate_region((void**)_address, size,
84 protection, false);
85 if (status != B_OK)
86 return status;
88 *_mappedAddress = (void*)*_address;
89 return B_OK;
92 static inline void*
93 Map(AddrType address)
95 return (void*)address;
99 typedef ELFLoader<ELF32Class> ELF32Loader;
100 #endif
103 #ifdef BOOT_SUPPORT_ELF64
104 struct ELF64Class {
105 static const uint8 kIdentClass = ELFCLASS64;
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;
118 static inline status_t
119 AllocateRegion(AddrType* _address, AddrType size, uint8 protection,
120 void **_mappedAddress)
122 #ifdef _BOOT_PLATFORM_EFI
123 void* address = (void*)*_address;
125 status_t status = platform_allocate_region(&address, size, protection,
126 false);
127 if (status != B_OK)
128 return status;
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.
136 void* address = (void*)(addr_t)(*_address & 0xffffffff);
138 status_t status = platform_allocate_region(&address, size, protection,
139 false);
140 if (status != B_OK)
141 return status;
143 *_mappedAddress = address;
144 *_address = (AddrType)(addr_t)address + KERNEL_LOAD_BASE_64_BIT
145 - KERNEL_LOAD_BASE;
146 #endif
147 return B_OK;
150 static inline void*
151 Map(AddrType address)
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);
158 return result;
159 #else
160 return (void*)(addr_t)(address - KERNEL_LOAD_BASE_64_BIT
161 + KERNEL_LOAD_BASE);
162 #endif
166 typedef ELFLoader<ELF64Class> ELF64Loader;
167 #endif
170 template<typename Class>
171 /*static*/ status_t
172 ELFLoader<Class>::Create(int fd, preloaded_image** _image)
174 ImageType* image = (ImageType*)kernel_args_malloc(sizeof(ImageType));
175 if (image == NULL)
176 return B_NO_MEMORY;
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;
184 const EhdrType& elfHeader = image->elf_header;
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;
195 image->elf_class = elfHeader.e_ident[EI_CLASS];
197 *_image = image;
198 return B_OK;
202 template<typename Class>
203 /*static*/ status_t
204 ELFLoader<Class>::Load(int fd, preloaded_image* _image)
206 size_t totalSize;
207 ssize_t length;
208 status_t status;
209 void* mappedRegion = NULL;
211 ImageType* image = static_cast<ImageType*>(_image);
212 const EhdrType& elfHeader = image->elf_header;
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;
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;
229 // create an area large enough to hold the image
231 image->data_region.size = 0;
232 image->text_region.size = 0;
234 for (int32 i = 0; i < elfHeader.e_phnum; i++) {
235 PhdrType& header = programHeaders[i];
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;
254 RegionType* region;
255 if (header.IsReadWrite()) {
256 if (image->data_region.size != 0) {
257 dprintf("elf: rw already handled!\n");
258 continue;
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;
266 region = &image->text_region;
267 } else
268 continue;
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;
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));
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;
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;
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;
308 // initialize the region pointers to the allocated region
309 secondRegion->start += firstRegion->start + firstRegion->delta;
311 image->data_region.delta += image->data_region.start;
312 image->text_region.delta += image->text_region.start;
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));
321 // load program data
323 for (int32 i = 0; i < elfHeader.e_phnum; i++) {
324 PhdrType& header = programHeaders[i];
326 if (header.p_type != PT_LOAD)
327 continue;
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;
337 TRACE(("load segment %ld (%llu bytes) mapped at %p...\n", i,
338 (uint64)header.p_filesz, Class::Map(region->start)));
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;
349 // Clear anything above the file size (that may also contain the BSS
350 // area)
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);
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;
362 image->num_debug_symbols = 0;
363 image->debug_symbols = NULL;
364 image->debug_string_table = NULL;
366 if (sLoadElfSymbols)
367 _LoadSymbolTable(fd, image);
369 free(programHeaders);
371 return B_OK;
373 error2:
374 if (mappedRegion != NULL)
375 platform_free_region(mappedRegion, totalSize);
376 error1:
377 free(programHeaders);
378 kernel_args_free(image);
380 return status;
384 template<typename Class>
385 /*static*/ status_t
386 ELFLoader<Class>::Relocate(preloaded_image* _image)
388 ImageType* image = static_cast<ImageType*>(_image);
390 status_t status = _ParseDynamicSection(image);
391 if (status != B_OK)
392 return status;
394 // deal with the rels first
395 if (image->rel) {
396 TRACE(("total %i relocs\n",
397 (int)image->rel_len / (int)sizeof(RelType)));
399 status = boot_arch_elf_relocate_rel(image, image->rel, image->rel_len);
400 if (status != B_OK)
401 return status;
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)));
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)));
416 status = boot_arch_elf_relocate_rela(image, (RelaType*)pltrel,
417 image->pltrel_len);
419 if (status != B_OK)
420 return status;
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;
432 return B_OK;
435 template<typename Class>
436 /*static*/ status_t
437 ELFLoader<Class>::Resolve(ImageType* image, SymType* symbol,
438 AddrType* symbolAddress)
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;
461 template<typename Class>
462 /*static*/ status_t
463 ELFLoader<Class>::_LoadSymbolTable(int fd, ImageType* image)
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;
472 // get section headers
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;
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;
488 // find symbol table in section headers
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];
494 if (stringHeader->sh_type != SHT_STRTAB) {
495 TRACE(("doesn't link to string table\n"));
496 status = B_BAD_DATA;
497 goto error1;
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;
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;
516 numSymbols = size / sizeof(SymType);
517 break;
521 if (symbolTable == NULL) {
522 TRACE(("no symbol table\n"));
523 status = B_BAD_VALUE;
524 goto error1;
527 // read in string table
529 size = stringHeader->sh_size;
530 stringTable = (char*)kernel_args_malloc(size);
531 if (stringTable == NULL) {
532 status = B_NO_MEMORY;
533 goto error2;
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;
543 TRACE(("loaded %ld debug symbols\n", numSymbols));
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;
551 free(sectionHeaders);
552 return B_OK;
554 error3:
555 kernel_args_free(stringTable);
556 error2:
557 kernel_args_free(symbolTable);
558 error1:
559 free(sectionHeaders);
561 return status;
565 template<typename Class>
566 /*static*/ status_t
567 ELFLoader<Class>::_ParseDynamicSection(ImageType* image)
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;
578 if(image->dynamic_section.start == 0)
579 return B_ERROR;
581 DynType* d = (DynType*)Class::Map(image->dynamic_section.start);
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;
617 default:
618 continue;
622 // lets make sure we found all the required sections
623 if (image->syms == NULL)
624 return B_ERROR;
626 return B_OK;
630 // #pragma mark -
633 void
634 elf_init()
636 // TODO: This cannot work, since the driver settings are loaded *after* the
637 // kernel has been loaded successfully.
638 #if 0
639 void *settings = load_driver_settings("kernel");
640 if (settings == NULL)
641 return;
643 sLoadElfSymbols = !get_driver_boolean_parameter(settings, "load_symbols",
644 false, false);
645 unload_driver_settings(settings);
646 #endif
650 status_t
651 elf_load_image(int fd, preloaded_image** _image)
653 status_t status = B_ERROR;
655 TRACE(("elf_load_image(fd = %d, _image = %p)\n", fd, _image));
657 #if BOOT_SUPPORT_ELF64
658 if (gKernelArgs.kernel_image == NULL
659 || gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
660 status = ELF64Loader::Create(fd, _image);
661 if (status == B_OK)
662 return ELF64Loader::Load(fd, *_image);
663 else if (status != B_BAD_TYPE)
664 return status;
666 #endif
667 #if BOOT_SUPPORT_ELF32
668 if (gKernelArgs.kernel_image == NULL
669 || gKernelArgs.kernel_image->elf_class == ELFCLASS32) {
670 status = ELF32Loader::Create(fd, _image);
671 if (status == B_OK)
672 return ELF32Loader::Load(fd, *_image);
674 #endif
676 return status;
680 status_t
681 elf_load_image(Directory* directory, const char* path)
683 preloaded_image* image;
685 TRACE(("elf_load_image(directory = %p, \"%s\")\n", directory, path));
687 int fd = open_from(directory, path, O_RDONLY);
688 if (fd < 0)
689 return fd;
691 // check if this file has already been loaded
693 struct stat stat;
694 if (fstat(fd, &stat) < 0)
695 return errno;
697 image = gKernelArgs.preloaded_images;
698 for (; image != NULL; image = image->next) {
699 if (image->inode == stat.st_ino) {
700 // file has already been loaded, no need to load it twice!
701 close(fd);
702 return B_OK;
706 // we still need to load it, so do it
708 status_t status = elf_load_image(fd, &image);
709 if (status == B_OK) {
710 image->name = kernel_args_strdup(path);
711 image->inode = stat.st_ino;
713 // insert to kernel args
714 image->next = gKernelArgs.preloaded_images;
715 gKernelArgs.preloaded_images = image;
716 } else
717 kernel_args_free(image);
719 close(fd);
720 return status;
724 status_t
725 elf_relocate_image(preloaded_image* image)
727 #ifdef BOOT_SUPPORT_ELF64
728 if (image->elf_class == ELFCLASS64)
729 return ELF64Loader::Relocate(image);
730 else
731 #endif
732 #ifdef BOOT_SUPPORT_ELF32
733 return ELF32Loader::Relocate(image);
734 #else
735 return B_ERROR;
736 #endif
740 #ifdef BOOT_SUPPORT_ELF32
741 status_t
742 boot_elf_resolve_symbol(preloaded_elf32_image* image, Elf32_Sym* symbol,
743 Elf32_Addr* symbolAddress)
745 return ELF32Loader::Resolve(image, symbol, symbolAddress);
747 #endif
750 #ifdef BOOT_SUPPORT_ELF64
751 status_t
752 boot_elf_resolve_symbol(preloaded_elf64_image* image, Elf64_Sym* symbol,
753 Elf64_Addr* symbolAddress)
755 return ELF64Loader::Resolve(image, symbol, symbolAddress);
758 void
759 boot_elf64_set_relocation(Elf64_Addr resolveAddress, Elf64_Addr finalAddress)
761 Elf64_Addr* dest = (Elf64_Addr*)ELF64Class::Map(resolveAddress);
762 *dest = finalAddress;
764 #endif