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.
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>
16 #include <SupportDefs.h>
25 # define TRACE(x) dprintf x
31 static bool sLoadElfSymbols
= true;
34 // #pragma mark - Generic ELF loader
37 template<typename Class
>
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
;
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
);
59 static status_t
_LoadSymbolTable(int fd
, ImageType
* image
);
60 static status_t
_ParseDynamicSection(ImageType
* image
);
64 #ifdef BOOT_SUPPORT_ELF32
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
,
88 *_mappedAddress
= (void*)*_address
;
95 return (void*)address
;
99 typedef ELFLoader
<ELF32Class
> ELF32Loader
;
103 #ifdef BOOT_SUPPORT_ELF64
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
,
130 *_mappedAddress
= address
;
131 platform_bootloader_address_to_kernel_address(address
, _address
);
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
,
143 *_mappedAddress
= address
;
144 *_address
= (AddrType
)(addr_t
)address
+ KERNEL_LOAD_BASE_64_BIT
151 Map(AddrType address
)
153 #ifdef _BOOT_PLATFORM_EFI
155 if (platform_kernel_address_to_bootloader_address(address
, &result
) != B_OK
) {
156 panic("Couldn't convert address %#lx", address
);
160 return (void*)(addr_t
)(address
- KERNEL_LOAD_BASE_64_BIT
166 typedef ELFLoader
<ELF64Class
> ELF64Loader
;
170 template<typename Class
>
172 ELFLoader
<Class
>::Create(int fd
, preloaded_image
** _image
)
174 ImageType
* image
= (ImageType
*)kernel_args_malloc(sizeof(ImageType
));
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
);
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
);
195 image
->elf_class
= elfHeader
.e_ident
[EI_CLASS
];
202 template<typename Class
>
204 ELFLoader
<Class
>::Load(int fd
, preloaded_image
* _image
)
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
;
222 length
= read_pos(fd
, elfHeader
.e_phoff
, programHeaders
, size
);
224 TRACE(("error reading in program headers\n"));
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
) {
241 image
->dynamic_section
.start
= header
.p_vaddr
;
242 image
->dynamic_section
.size
= header
.p_memsz
;
247 // known but unused type
250 dprintf("unhandled pheader type 0x%" B_PRIx32
"\n", header
.p_type
);
255 if (header
.IsReadWrite()) {
256 if (image
->data_region
.size
!= 0) {
257 dprintf("elf: rw already handled!\n");
260 region
= &image
->data_region
;
261 } else if (header
.IsExecutable()) {
262 if (image
->text_region
.size
!= 0) {
263 dprintf("elf: ro already handled!\n");
266 region
= &image
->text_region
;
270 region
->start
= ROUNDDOWN(header
.p_vaddr
, B_PAGE_SIZE
);
271 region
->size
= ROUNDUP(header
.p_memsz
+ (header
.p_vaddr
% 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");
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
;
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
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
;
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
));
323 for (int32 i
= 0; i
< elfHeader
.e_phnum
; i
++) {
324 PhdrType
& header
= programHeaders
[i
];
326 if (header
.p_type
!= PT_LOAD
)
330 if (header
.IsReadWrite())
331 region
= &image
->data_region
;
332 else if (header
.IsExecutable())
333 region
= &image
->text_region
;
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
)),
343 if (length
< (ssize_t
)header
.p_filesz
) {
345 dprintf("error reading in seg %" B_PRId32
"\n", i
);
349 // Clear anything above the file size (that may also contain the BSS
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
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
;
367 _LoadSymbolTable(fd
, image
);
369 free(programHeaders
);
374 if (mappedRegion
!= NULL
)
375 platform_free_region(mappedRegion
, totalSize
);
377 free(programHeaders
);
378 kernel_args_free(image
);
384 template<typename Class
>
386 ELFLoader
<Class
>::Relocate(preloaded_image
* _image
)
388 ImageType
* image
= static_cast<ImageType
*>(_image
);
390 status_t status
= _ParseDynamicSection(image
);
394 // deal with the rels first
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
);
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
,
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
,
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
,
435 template<typename Class
>
437 ELFLoader
<Class
>::Resolve(ImageType
* image
, SymType
* symbol
,
438 AddrType
* symbolAddress
)
440 switch (symbol
->st_shndx
) {
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
;
447 *symbolAddress
= symbol
->st_value
;
451 TRACE(("elf_resolve_symbol: COMMON symbol, finish me!\n"));
455 *symbolAddress
= symbol
->st_value
+ image
->text_region
.delta
;
461 template<typename Class
>
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;
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");
481 ssize_t length
= read_pos(fd
, elfHeader
.e_shoff
, sectionHeaders
, size
);
483 TRACE(("error reading in program headers\n"));
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
= §ionHeaders
[sectionHeaders
[i
].sh_link
];
494 if (stringHeader
->sh_type
!= SHT_STRTAB
) {
495 TRACE(("doesn't link to string table\n"));
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
;
508 length
= read_pos(fd
, sectionHeaders
[i
].sh_offset
, symbolTable
,
511 TRACE(("error reading in symbol table\n"));
516 numSymbols
= size
/ sizeof(SymType
);
521 if (symbolTable
== NULL
) {
522 TRACE(("no symbol table\n"));
523 status
= B_BAD_VALUE
;
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
;
536 length
= read_pos(fd
, stringHeader
->sh_offset
, stringTable
, size
);
538 TRACE(("error reading in string table\n"));
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
);
555 kernel_args_free(stringTable
);
557 kernel_args_free(symbolTable
);
559 free(sectionHeaders
);
565 template<typename Class
>
567 ELFLoader
<Class
>::_ParseDynamicSection(ImageType
* image
)
575 image
->pltrel_len
= 0;
576 image
->pltrel_type
= 0;
578 if(image
->dynamic_section
.start
== 0)
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
) {
589 image
->syms
= (SymType
*)Class::Map(d
[i
].d_un
.d_ptr
590 + image
->text_region
.delta
);
593 image
->rel
= (RelType
*)Class::Map(d
[i
].d_un
.d_ptr
594 + image
->text_region
.delta
);
597 image
->rel_len
= d
[i
].d_un
.d_val
;
600 image
->rela
= (RelaType
*)Class::Map(d
[i
].d_un
.d_ptr
601 + image
->text_region
.delta
);
604 image
->rela_len
= d
[i
].d_un
.d_val
;
607 image
->pltrel
= (RelType
*)Class::Map(d
[i
].d_un
.d_ptr
608 + image
->text_region
.delta
);
611 image
->pltrel_len
= d
[i
].d_un
.d_val
;
614 image
->pltrel_type
= d
[i
].d_un
.d_val
;
622 // lets make sure we found all the required sections
623 if (image
->syms
== NULL
)
636 // TODO: This cannot work, since the driver settings are loaded *after* the
637 // kernel has been loaded successfully.
639 void *settings
= load_driver_settings("kernel");
640 if (settings
== NULL
)
643 sLoadElfSymbols
= !get_driver_boolean_parameter(settings
, "load_symbols",
645 unload_driver_settings(settings
);
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
);
662 return ELF64Loader::Load(fd
, *_image
);
663 else if (status
!= B_BAD_TYPE
)
667 #if BOOT_SUPPORT_ELF32
668 if (gKernelArgs
.kernel_image
== NULL
669 || gKernelArgs
.kernel_image
->elf_class
== ELFCLASS32
) {
670 status
= ELF32Loader::Create(fd
, _image
);
672 return ELF32Loader::Load(fd
, *_image
);
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
);
691 // check if this file has already been loaded
694 if (fstat(fd
, &stat
) < 0)
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!
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
;
717 kernel_args_free(image
);
725 elf_relocate_image(preloaded_image
* image
)
727 #ifdef BOOT_SUPPORT_ELF64
728 if (image
->elf_class
== ELFCLASS64
)
729 return ELF64Loader::Relocate(image
);
732 #ifdef BOOT_SUPPORT_ELF32
733 return ELF32Loader::Relocate(image
);
740 #ifdef BOOT_SUPPORT_ELF32
742 boot_elf_resolve_symbol(preloaded_elf32_image
* image
, Elf32_Sym
* symbol
,
743 Elf32_Addr
* symbolAddress
)
745 return ELF32Loader::Resolve(image
, symbol
, symbolAddress
);
750 #ifdef BOOT_SUPPORT_ELF64
752 boot_elf_resolve_symbol(preloaded_elf64_image
* image
, Elf64_Sym
* symbol
,
753 Elf64_Addr
* symbolAddress
)
755 return ELF64Loader::Resolve(image
, symbol
, symbolAddress
);
759 boot_elf64_set_relocation(Elf64_Addr resolveAddress
, Elf64_Addr finalAddress
)
761 Elf64_Addr
* dest
= (Elf64_Addr
*)ELF64Class::Map(resolveAddress
);
762 *dest
= finalAddress
;