/*static*/ status_t ELFLoader<Class>::Load(int fd, preloaded_image* _image) { size_t totalSize; ssize_t length; status_t status; void* mappedRegion = NULL; ImageType* image = static_cast<ImageType*>(_image); const EhdrType& elfHeader = image->elf_header; ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize; PhdrType* programHeaders = (PhdrType*)malloc(size); if (programHeaders == NULL) { dprintf("error allocating space for program headers\n"); status = B_NO_MEMORY; goto error1; } length = read_pos(fd, elfHeader.e_phoff, programHeaders, size); if (length < size) { TRACE(("error reading in program headers\n")); status = B_ERROR; goto error1; } // create an area large enough to hold the image image->data_region.size = 0; image->text_region.size = 0; for (int32 i = 0; i < elfHeader.e_phnum; i++) { PhdrType& header = programHeaders[i]; switch (header.p_type) { case PT_LOAD: break; case PT_DYNAMIC: image->dynamic_section.start = header.p_vaddr; image->dynamic_section.size = header.p_memsz; continue; case PT_INTERP: case PT_PHDR: case PT_ARM_UNWIND: // known but unused type continue; default: dprintf("unhandled pheader type 0x%" B_PRIx32 "\n", header.p_type); continue; } RegionType* region; if (header.IsReadWrite()) { if (image->data_region.size != 0) { dprintf("elf: rw already handled!\n"); continue; } region = &image->data_region; } else if (header.IsExecutable()) { if (image->text_region.size != 0) { dprintf("elf: ro already handled!\n"); continue; } region = &image->text_region; } else continue; region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE); region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); region->delta = -region->start; TRACE(("segment %ld: start = 0x%llx, size = %llu, delta = %llx\n", i, (uint64)region->start, (uint64)region->size, (int64)(AddrType)region->delta)); } // found both, text and data? if (image->data_region.size == 0 || image->text_region.size == 0) { dprintf("Couldn't find both text and data segment!\n"); status = B_BAD_DATA; goto error1; } // get the segment order RegionType* firstRegion; RegionType* secondRegion; if (image->text_region.start < image->data_region.start) { firstRegion = &image->text_region; secondRegion = &image->data_region; } else { firstRegion = &image->data_region; secondRegion = &image->text_region; } // The kernel and the modules are relocatable, thus AllocateRegion() // can automatically allocate an address, but shall prefer the specified // base address. totalSize = secondRegion->start + secondRegion->size - firstRegion->start; if (Class::AllocateRegion(&firstRegion->start, totalSize, B_READ_AREA | B_WRITE_AREA, &mappedRegion) != B_OK) { status = B_NO_MEMORY; goto error1; } // initialize the region pointers to the allocated region secondRegion->start += firstRegion->start + firstRegion->delta; image->data_region.delta += image->data_region.start; image->text_region.delta += image->text_region.start; TRACE(("text: start 0x%llx, size 0x%llx, delta 0x%llx\n", (uint64)image->text_region.start, (uint64)image->text_region.size, (int64)(AddrType)image->text_region.delta)); TRACE(("data: start 0x%llx, size 0x%llx, delta 0x%llx\n", (uint64)image->data_region.start, (uint64)image->data_region.size, (int64)(AddrType)image->data_region.delta)); // load program data for (int32 i = 0; i < elfHeader.e_phnum; i++) { PhdrType& header = programHeaders[i]; if (header.p_type != PT_LOAD) continue; RegionType* region; if (header.IsReadWrite()) region = &image->data_region; else if (header.IsExecutable()) region = &image->text_region; else continue; TRACE(("load segment %ld (%llu bytes) mapped at %p...\n", i, (uint64)header.p_filesz, Class::Map(region->start))); length = read_pos(fd, header.p_offset, Class::Map(region->start + (header.p_vaddr % B_PAGE_SIZE)), header.p_filesz); if (length < (ssize_t)header.p_filesz) { status = B_BAD_DATA; dprintf("error reading in seg %" B_PRId32 "\n", i); goto error2; } // Clear anything above the file size (that may also contain the BSS // area) uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; if (offset < region->size) memset(Class::Map(region->start + offset), 0, region->size - offset); } // offset dynamic section, and program entry addresses by the delta of the // regions image->dynamic_section.start += image->text_region.delta; image->elf_header.e_entry += image->text_region.delta; image->num_debug_symbols = 0; image->debug_symbols = NULL; image->debug_string_table = NULL; if (sLoadElfSymbols) _LoadSymbolTable(fd, image); free(programHeaders); return B_OK; error2: if (mappedRegion != NULL) platform_free_region(mappedRegion, totalSize); error1: free(programHeaders); kernel_args_free(image); return status; }
inline void operator()(void* memory) { if (memory != NULL) platform_free_region(memory, kTarRegionSize); }
status_t elf_load_image(int fd, preloaded_image *image) { size_t totalSize; status_t status; TRACE(("elf_load_image(fd = %d, image = %p)\n", fd, image)); struct Elf32_Ehdr &elfHeader = image->elf_header; ssize_t length = read_pos(fd, 0, &elfHeader, sizeof(Elf32_Ehdr)); if (length < (ssize_t)sizeof(Elf32_Ehdr)) return B_BAD_TYPE; status = verify_elf_header(elfHeader); if (status < B_OK) return status; ssize_t size = elfHeader.e_phnum * elfHeader.e_phentsize; Elf32_Phdr *programHeaders = (struct Elf32_Phdr *)malloc(size); if (programHeaders == NULL) { dprintf("error allocating space for program headers\n"); return B_NO_MEMORY; } length = read_pos(fd, elfHeader.e_phoff, programHeaders, size); if (length < size) { TRACE(("error reading in program headers\n")); status = B_ERROR; goto error1; } // create an area large enough to hold the image image->data_region.size = 0; image->text_region.size = 0; for (int32 i = 0; i < elfHeader.e_phnum; i++) { Elf32_Phdr &header = programHeaders[i]; switch (header.p_type) { case PT_LOAD: break; case PT_DYNAMIC: image->dynamic_section.start = header.p_vaddr; image->dynamic_section.size = header.p_memsz; continue; case PT_INTERP: case PT_PHDR: // known but unused type continue; default: dprintf("unhandled pheader type 0x%lx\n", header.p_type); continue; } elf_region *region; if (header.IsReadWrite()) { if (image->data_region.size != 0) { dprintf("elf: rw already handled!\n"); continue; } region = &image->data_region; } else if (header.IsExecutable()) { if (image->text_region.size != 0) { dprintf("elf: ro already handled!\n"); continue; } region = &image->text_region; } else continue; region->start = ROUNDDOWN(header.p_vaddr, B_PAGE_SIZE); region->size = ROUNDUP(header.p_memsz + (header.p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); region->delta = -region->start; TRACE(("segment %d: start = %p, size = %lu, delta = %lx\n", i, region->start, region->size, region->delta)); } // found both, text and data? if (image->data_region.size == 0 || image->text_region.size == 0) { dprintf("Couldn't find both text and data segment!\n"); status = B_BAD_DATA; goto error1; } // get the segment order elf_region *firstRegion; elf_region *secondRegion; if (image->text_region.start < image->data_region.start) { firstRegion = &image->text_region; secondRegion = &image->data_region; } else { firstRegion = &image->data_region; secondRegion = &image->text_region; } // Check whether the segments have an unreasonable amount of unused space // inbetween. totalSize = secondRegion->start + secondRegion->size - firstRegion->start; if (totalSize > image->text_region.size + image->data_region.size + 8 * 1024) { status = B_BAD_DATA; goto error1; } // The kernel and the modules are relocatable, thus // platform_allocate_region() can automatically allocate an address, // but shall prefer the specified base address. if (platform_allocate_region((void **)&firstRegion->start, totalSize, B_READ_AREA | B_WRITE_AREA, false) < B_OK) { status = B_NO_MEMORY; goto error1; } // initialize the region pointers to the allocated region secondRegion->start += firstRegion->start + firstRegion->delta; image->data_region.delta += image->data_region.start; image->text_region.delta += image->text_region.start; // load program data for (int i = 0; i < elfHeader.e_phnum; i++) { Elf32_Phdr &header = programHeaders[i]; if (header.p_type != PT_LOAD) continue; elf_region *region; if (header.IsReadWrite()) region = &image->data_region; else if (header.IsExecutable()) region = &image->text_region; else continue; TRACE(("load segment %d (%ld bytes)...\n", i, header.p_filesz)); length = read_pos(fd, header.p_offset, (void *)(region->start + (header.p_vaddr % B_PAGE_SIZE)), header.p_filesz); if (length < (ssize_t)header.p_filesz) { status = B_BAD_DATA; dprintf("error reading in seg %d\n", i); goto error2; } // Clear anything above the file size (that may also contain the BSS // area) uint32 offset = (header.p_vaddr % B_PAGE_SIZE) + header.p_filesz; if (offset < region->size) memset((void *)(region->start + offset), 0, region->size - offset); } // offset dynamic section, and program entry addresses by the delta of the // regions image->dynamic_section.start += image->text_region.delta; image->elf_header.e_entry += image->text_region.delta; image->num_debug_symbols = 0; image->debug_symbols = NULL; image->debug_string_table = NULL; if (sLoadElfSymbols) load_elf_symbol_table(fd, image); free(programHeaders); return B_OK; error2: if (image->text_region.start != 0) platform_free_region((void *)image->text_region.start, totalSize); error1: free(programHeaders); return status; }