From c14a34a65f69bbccfca75a0c9cd44bab21ab25d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 26 Mar 2006 15:58:43 +0000 Subject: [PATCH] * Improved kernel ELF loader (and made it more similar to the one from the boot loader): it now supports holes between segments, and accepts any segment order. * Renamed elf.c to elf.cpp and fixed warnings. * Renamed elf_image_info::dynamic_ptr and eheader to dynamic_section and elf_header. * Some cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16878 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/elf32.h | 9 +- headers/private/kernel/elf_priv.h | 13 +- src/system/kernel/Jamfile | 2 +- src/system/kernel/{elf.c => elf.cpp} | 308 ++++++++++++++------------- 4 files changed, 179 insertions(+), 153 deletions(-) rename src/system/kernel/{elf.c => elf.cpp} (81%) diff --git a/headers/private/kernel/elf32.h b/headers/private/kernel/elf32.h index 62468e046d..19ddc0f0eb 100644 --- a/headers/private/kernel/elf32.h +++ b/headers/private/kernel/elf32.h @@ -1,7 +1,10 @@ /* -** Copyright 2001, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ + * Copyright 2002-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT license. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #ifndef _ELF32_H #define _ELF32_H diff --git a/headers/private/kernel/elf_priv.h b/headers/private/kernel/elf_priv.h index 21a3c17312..f924ceea8d 100644 --- a/headers/private/kernel/elf_priv.h +++ b/headers/private/kernel/elf_priv.h @@ -1,7 +1,10 @@ /* -** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ + * Copyright 2002-2006, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT license. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #ifndef _KERNEL_ELF_PRIV_H #define _KERNEL_ELF_PRIV_H @@ -25,10 +28,10 @@ struct elf_image_info { void *vnode; elf_region text_region; elf_region data_region; - addr_t dynamic_ptr; // pointer to the dynamic section + addr_t dynamic_section; // pointer to the dynamic section struct elf_linked_image *linked_images; - struct Elf32_Ehdr *eheader; + struct Elf32_Ehdr *elf_header; // pointer to symbol participation data structures char *needed; diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index a6a97c0c32..2636a79aeb 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -13,7 +13,7 @@ SubDir HAIKU_TOP src system kernel ; KernelMergeObject kernel_core.o : boot_item.cpp cpu.c - elf.c + elf.cpp heap.c image.c int.c diff --git a/src/system/kernel/elf.c b/src/system/kernel/elf.cpp similarity index 81% rename from src/system/kernel/elf.c rename to src/system/kernel/elf.cpp index bedf2c8100..d4e8e4d661 100644 --- a/src/system/kernel/elf.c +++ b/src/system/kernel/elf.cpp @@ -128,7 +128,7 @@ find_image_at_address(addr_t address) // get image that may contain the address - while ((image = hash_next(sImagesHash, &iterator)) != NULL) { + while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { if ((address >= image->text_region.start && address <= (image->text_region.start + image->text_region.size)) || (address >= image->data_region.start @@ -169,7 +169,7 @@ dump_address_info(int argc, char **argv) static struct elf_image_info * find_image(image_id id) { - return hash_lookup(sImagesHash, (void *)id); + return (elf_image_info *)hash_lookup(sImagesHash, (void *)id); } @@ -182,7 +182,7 @@ find_image_by_vnode(void *vnode) mutex_lock(&sImageMutex); hash_open(sImagesHash, &iterator); - while ((image = hash_next(sImagesHash, &iterator)) != NULL) { + while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { if (image->vnode == vnode) break; } @@ -275,7 +275,7 @@ dump_symbols(int argc, char **argv) // find image at address hash_open(sImagesHash, &iterator); - while ((image = hash_next(sImagesHash, &iterator)) != NULL) { + while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { if (image->text_region.start <= num && image->text_region.start + image->text_region.size >= num) break; @@ -285,14 +285,14 @@ dump_symbols(int argc, char **argv) if (image == NULL) kprintf("No image covers 0x%lx in the kernel!\n", num); } else { - image = hash_lookup(sImagesHash, (void *)num); + image = (elf_image_info *)hash_lookup(sImagesHash, (void *)num); if (image == NULL) kprintf("image 0x%lx doesn't exist in the kernel!\n", num); } } else { // look for image by name hash_open(sImagesHash, &iterator); - while ((image = hash_next(sImagesHash, &iterator)) != NULL) { + while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { if (!strcmp(image->name, argv[1])) break; } @@ -367,7 +367,7 @@ dump_image_info(struct elf_image_info *image) kprintf(" id 0x%lx\n", image->id); dump_elf_region(&image->text_region, "text"); dump_elf_region(&image->data_region, "data"); - kprintf(" dynamic_ptr 0x%lx\n", image->dynamic_ptr); + kprintf(" dynamic_section 0x%lx\n", image->dynamic_section); kprintf(" needed %p\n", image->needed); kprintf(" symhash %p\n", image->symhash); kprintf(" syms %p\n", image->syms); @@ -397,7 +397,7 @@ dump_image(int argc, char **argv) // semi-hack dump_image_info((struct elf_image_info *)num); } else { - image = hash_lookup(sImagesHash, (void *)num); + image = (elf_image_info *)hash_lookup(sImagesHash, (void *)num); if (image == NULL) kprintf("image 0x%lx doesn't exist in the kernel!\n", num); else @@ -410,7 +410,7 @@ dump_image(int argc, char **argv) hash_open(sImagesHash, &iterator); - while ((image = hash_next(sImagesHash, &iterator)) != NULL) { + while ((image = (elf_image_info *)hash_next(sImagesHash, &iterator)) != NULL) { kprintf("%p (%ld) %s\n", image, image->id, image->name); } @@ -443,7 +443,7 @@ elf_find_symbol(struct elf_image_info *image, const char *name) uint32 hash; uint32 i; - if (!image->dynamic_ptr) + if (!image->dynamic_section) return NULL; hash = elf_hash(name) % HASHTABSIZE(image); @@ -460,8 +460,7 @@ static status_t elf_parse_dynamic_section(struct elf_image_info *image) { struct Elf32_Dyn *d; - int i; - int needed_offset = -1; + int32 neededOffset = -1; TRACE(("top of elf_parse_dynamic_section\n")); @@ -469,14 +468,14 @@ elf_parse_dynamic_section(struct elf_image_info *image) image->syms = 0; image->strtab = 0; - d = (struct Elf32_Dyn *)image->dynamic_ptr; + d = (struct Elf32_Dyn *)image->dynamic_section; if (!d) return B_ERROR; - for (i = 0; d[i].d_tag != DT_NULL; i++) { + for (int32 i = 0; d[i].d_tag != DT_NULL; i++) { switch (d[i].d_tag) { case DT_NEEDED: - needed_offset = d[i].d_un.d_ptr + image->text_region.delta; + neededOffset = d[i].d_un.d_ptr + image->text_region.delta; break; case DT_HASH: image->symhash = (uint32 *)(d[i].d_un.d_ptr + image->text_region.delta); @@ -518,10 +517,10 @@ elf_parse_dynamic_section(struct elf_image_info *image) if (!image->symhash || !image->syms || !image->strtab) return B_ERROR; - TRACE(("needed_offset = %d\n", needed_offset)); + TRACE(("needed_offset = %d\n", neededOffset)); - if (needed_offset >= 0) - image->needed = STRING(image, needed_offset); + if (neededOffset >= 0) + image->needed = STRING(image, neededOffset); return B_OK; } @@ -621,18 +620,18 @@ elf_relocate(struct elf_image_info *image, const char *sym_prepend) static int -verify_eheader(struct Elf32_Ehdr *eheader) +verify_eheader(struct Elf32_Ehdr *elfHeader) { - if (memcmp(eheader->e_ident, ELF_MAGIC, 4) != 0) + if (memcmp(elfHeader->e_ident, ELF_MAGIC, 4) != 0) return B_NOT_AN_EXECUTABLE; - if (eheader->e_ident[4] != ELFCLASS32) + if (elfHeader->e_ident[4] != ELFCLASS32) return B_NOT_AN_EXECUTABLE; - if (eheader->e_phoff == 0) + if (elfHeader->e_phoff == 0) return B_NOT_AN_EXECUTABLE; - if (eheader->e_phentsize < sizeof(struct Elf32_Phdr)) + if (elfHeader->e_phentsize < sizeof(struct Elf32_Phdr)) return B_NOT_AN_EXECUTABLE; return 0; @@ -673,7 +672,7 @@ unload_elf_image(struct elf_image_info *image) unregister_elf_image(image); - free(image->eheader); + free(image->elf_header); free(image->name); free(image); @@ -684,7 +683,7 @@ unload_elf_image(struct elf_image_info *image) static status_t load_elf_symbol_table(int fd, struct elf_image_info *image) { - struct Elf32_Ehdr *elfHeader = image->eheader; + struct Elf32_Ehdr *elfHeader = image->elf_header; struct Elf32_Sym *symbolTable = NULL; struct Elf32_Shdr *stringHeader = NULL; uint32 numSymbols = 0; @@ -797,7 +796,7 @@ insert_preloaded_image(struct preloaded_image *preloadedImage, bool kernel) return B_NO_MEMORY; image->name = strdup(preloadedImage->name); - image->dynamic_ptr = preloadedImage->dynamic_section.start; + image->dynamic_section = preloadedImage->dynamic_section.start; image->text_region = preloadedImage->text_region; image->data_region = preloadedImage->data_region; @@ -1011,11 +1010,11 @@ symbol_found: status_t elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entry) { - struct Elf32_Ehdr eheader; - struct Elf32_Phdr *pheaders = NULL; + struct Elf32_Ehdr elfHeader; + struct Elf32_Phdr *programHeaders = NULL; char baseName[B_OS_NAME_LENGTH]; - status_t err; - ssize_t len; + status_t status; + ssize_t length; int fd; int i; @@ -1027,40 +1026,40 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr // read and verify the ELF header - len = _kern_read(fd, 0, &eheader, sizeof(eheader)); - if (len < 0) { - err = len; + length = _kern_read(fd, 0, &elfHeader, sizeof(elfHeader)); + if (length < B_OK) { + status = length; goto error; } - if (len != sizeof(eheader)) { + if (length != sizeof(elfHeader)) { // short read - err = B_NOT_AN_EXECUTABLE; + status = B_NOT_AN_EXECUTABLE; goto error; } - err = verify_eheader(&eheader); - if (err < 0) + status = verify_eheader(&elfHeader); + if (status < B_OK) goto error; // read program header - pheaders = (struct Elf32_Phdr *)malloc(eheader.e_phnum * eheader.e_phentsize); - if (pheaders == NULL) { + programHeaders = (struct Elf32_Phdr *)malloc(elfHeader.e_phnum * elfHeader.e_phentsize); + if (programHeaders == NULL) { dprintf("error allocating space for program headers\n"); - err = B_NO_MEMORY; + status = B_NO_MEMORY; goto error; } - TRACE(("reading in program headers at 0x%lx, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize)); - len = _kern_read(fd, eheader.e_phoff, pheaders, eheader.e_phnum * eheader.e_phentsize); - if (len < 0) { - err = len; + TRACE(("reading in program headers at 0x%lx, length 0x%x\n", elfHeader.e_phoff, elfHeader.e_phnum * elfHeader.e_phentsize)); + length = _kern_read(fd, elfHeader.e_phoff, programHeaders, elfHeader.e_phnum * elfHeader.e_phentsize); + if (length < B_OK) { + status = length; dprintf("error reading in program headers\n"); goto error; } - if (len != eheader.e_phnum * eheader.e_phentsize) { + if (length != elfHeader.e_phnum * elfHeader.e_phentsize) { dprintf("short read while reading in program headers\n"); - err = -1; + status = -1; goto error; } @@ -1083,21 +1082,21 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr // map the program's segments into memory - for (i = 0; i < eheader.e_phnum; i++) { + for (i = 0; i < elfHeader.e_phnum; i++) { char regionName[B_OS_NAME_LENGTH]; char *regionAddress; area_id id; - if (pheaders[i].p_type != PT_LOAD) + if (programHeaders[i].p_type != PT_LOAD) continue; - regionAddress = (char *)ROUNDOWN(pheaders[i].p_vaddr, B_PAGE_SIZE); - if (pheaders[i].p_flags & PF_WRITE) { + regionAddress = (char *)ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); + if (programHeaders[i].p_flags & PF_WRITE) { /* * rw/data segment */ - uint32 memUpperBound = (pheaders[i].p_vaddr % B_PAGE_SIZE) + pheaders[i].p_memsz; - uint32 fileUpperBound = (pheaders[i].p_vaddr % B_PAGE_SIZE) + pheaders[i].p_filesz; + uint32 memUpperBound = (programHeaders[i].p_vaddr % B_PAGE_SIZE) + programHeaders[i].p_memsz; + uint32 fileUpperBound = (programHeaders[i].p_vaddr % B_PAGE_SIZE) + programHeaders[i].p_filesz; memUpperBound = ROUNDUP(memUpperBound, B_PAGE_SIZE); fileUpperBound = ROUNDUP(fileUpperBound, B_PAGE_SIZE); @@ -1109,10 +1108,10 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr B_EXACT_ADDRESS, fileUpperBound, B_READ_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP, - path, ROUNDOWN(pheaders[i].p_offset, B_PAGE_SIZE)); + path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); if (id < B_OK) { dprintf("error mapping file data: %s!\n", strerror(id)); - err = B_NOT_AN_EXECUTABLE; + status = B_NOT_AN_EXECUTABLE; goto error; } @@ -1120,11 +1119,11 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr // at least parts of it are the bss and have to be zeroed) { uint32 start = (uint32)regionAddress - + (pheaders[i].p_vaddr % B_PAGE_SIZE) - + pheaders[i].p_filesz; + + (programHeaders[i].p_vaddr % B_PAGE_SIZE) + + programHeaders[i].p_filesz; uint32 amount = fileUpperBound - - (pheaders[i].p_vaddr % B_PAGE_SIZE) - - (pheaders[i].p_filesz); + - (programHeaders[i].p_vaddr % B_PAGE_SIZE) + - (programHeaders[i].p_filesz); memset((void *)start, 0, amount); } @@ -1141,7 +1140,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr B_EXACT_ADDRESS, bss_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); if (id < B_OK) { dprintf("error allocating bss area: %s!\n", strerror(id)); - err = B_NOT_AN_EXECUTABLE; + status = B_NOT_AN_EXECUTABLE; goto error; } } @@ -1154,12 +1153,12 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr id = vm_map_file(team->id, regionName, (void **)®ionAddress, B_EXACT_ADDRESS, - ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE), + ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE), B_READ_AREA | B_EXECUTE_AREA, REGION_PRIVATE_MAP, - path, ROUNDOWN(pheaders[i].p_offset, B_PAGE_SIZE)); + path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE)); if (id < B_OK) { dprintf("error mapping file text: %s!\n", strerror(id)); - err = B_NOT_AN_EXECUTABLE; + status = B_NOT_AN_EXECUTABLE; goto error; } } @@ -1167,36 +1166,33 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr TRACE(("elf_load: done!\n")); - *entry = eheader.e_entry; + *entry = elfHeader.e_entry; - err = B_OK; + status = B_OK; error: - if (pheaders) - free(pheaders); + if (programHeaders) + free(programHeaders); _kern_close(fd); - return err; + return status; } image_id load_kernel_add_on(const char *path) { - bool ro_segment_handled = false; - bool rw_segment_handled = false; - struct Elf32_Ehdr *eheader; - struct Elf32_Phdr *pheaders; + struct Elf32_Phdr *programHeaders; + struct Elf32_Ehdr *elfHeader; struct elf_image_info *image; const char *fileName; void *vnode = NULL; void *reservedAddress; addr_t start; size_t reservedSize; + status_t status; int fd; - int err; - int i; - ssize_t len; + ssize_t length; TRACE(("elf_load_kspace: entry path '%s'\n", path)); @@ -1204,8 +1200,8 @@ load_kernel_add_on(const char *path) if (fd < 0) return fd; - err = vfs_get_vnode_from_fd(fd, true, &vnode); - if (err < 0) + status = vfs_get_vnode_from_fd(fd, true, &vnode); + if (status < B_OK) goto error0; // get the file name @@ -1215,77 +1211,90 @@ load_kernel_add_on(const char *path) else fileName++; - // XXX awful hack to keep someone else from trying to load this image - // probably not a bad thing, shouldn't be too many races + // Prevent someone else from trying to load this image mutex_lock(&sImageLoadMutex); // make sure it's not loaded already. Search by vnode image = find_image_by_vnode(vnode); if (image) { atomic_add(&image->ref_count, 1); - //err = ERR_NOT_ALLOWED; goto done; } - eheader = (struct Elf32_Ehdr *)malloc(sizeof(*eheader)); - if (!eheader) { - err = B_NO_MEMORY; + elfHeader = (struct Elf32_Ehdr *)malloc(sizeof(*elfHeader)); + if (!elfHeader) { + status = B_NO_MEMORY; goto error; } - len = _kern_read(fd, 0, eheader, sizeof(*eheader)); - if (len < 0) { - err = len; + length = _kern_read(fd, 0, elfHeader, sizeof(*elfHeader)); + if (length < B_OK) { + status = length; goto error1; } - if (len != sizeof(*eheader)) { + if (length != sizeof(*elfHeader)) { // short read - err = B_NOT_AN_EXECUTABLE; + status = B_NOT_AN_EXECUTABLE; goto error1; } - err = verify_eheader(eheader); - if (err < 0) + status = verify_eheader(elfHeader); + if (status < B_OK) goto error1; image = create_image_struct(); if (!image) { - err = B_NO_MEMORY; + status = B_NO_MEMORY; goto error1; } image->vnode = vnode; - image->eheader = eheader; + image->elf_header = elfHeader; image->name = strdup(path); - pheaders = (struct Elf32_Phdr *)malloc(eheader->e_phnum * eheader->e_phentsize); - if (pheaders == NULL) { + programHeaders = (struct Elf32_Phdr *)malloc(elfHeader->e_phnum * elfHeader->e_phentsize); + if (programHeaders == NULL) { dprintf("%s: error allocating space for program headers\n", fileName); - err = B_NO_MEMORY; + status = B_NO_MEMORY; goto error2; } - TRACE(("reading in program headers at 0x%lx, len 0x%x\n", eheader->e_phoff, eheader->e_phnum * eheader->e_phentsize)); - len = _kern_read(fd, eheader->e_phoff, pheaders, eheader->e_phnum * eheader->e_phentsize); - if (len < 0) { - err = len; + TRACE(("reading in program headers at 0x%lx, length 0x%x\n", elfHeader->e_phoff, elfHeader->e_phnum * elfHeader->e_phentsize)); + length = _kern_read(fd, elfHeader->e_phoff, programHeaders, elfHeader->e_phnum * elfHeader->e_phentsize); + if (length < B_OK) { + status = length; TRACE(("%s: error reading in program headers\n", fileName)); goto error3; } - if (len != eheader->e_phnum * eheader->e_phentsize) { + if (length != elfHeader->e_phnum * elfHeader->e_phentsize) { TRACE(("%s: short read while reading in program headers\n", fileName)); - err = -1; + status = B_ERROR; goto error3; } // determine how much space we need for all loaded segments reservedSize = 0; + length = 0; - for (i = 0; i < eheader->e_phnum; i++) { - if (pheaders[i].p_type != PT_LOAD) + for (int32 i = 0; i < elfHeader->e_phnum; i++) { + size_t end; + + if (programHeaders[i].p_type != PT_LOAD) continue; - reservedSize += ROUNDUP(pheaders[i].p_memsz - + (pheaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); + length += ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); +dprintf("[%ld] vaddr: %lx, memsz: %lx\n", i, programHeaders[i].p_vaddr, + programHeaders[i].p_memsz); + end = ROUNDUP(programHeaders[i].p_memsz + programHeaders[i].p_vaddr, B_PAGE_SIZE); + if (end > reservedSize) + reservedSize = end; + } +dprintf("-> reserved size %lx, length %lx\n", reservedSize, length); + + // Check whether the segments have an unreasonable amount of unused space + // inbetween. + if ((ssize_t)reservedSize > length + 8 * 1024) { + status = B_BAD_DATA; + goto error1; } // reserve that space and allocate the areas from that one @@ -1294,105 +1303,116 @@ load_kernel_add_on(const char *path) goto error3; start = (addr_t)reservedAddress; + image->data_region.size = 0; + image->text_region.size = 0; - for (i = 0; i < eheader->e_phnum; i++) { + for (int32 i = 0; i < elfHeader->e_phnum; i++) { char regionName[B_OS_NAME_LENGTH]; elf_region *region; TRACE(("looking at program header %d\n", i)); - switch (pheaders[i].p_type) { + switch (programHeaders[i].p_type) { case PT_LOAD: break; case PT_DYNAMIC: - image->dynamic_ptr = pheaders[i].p_vaddr; + image->dynamic_section = programHeaders[i].p_vaddr; continue; default: - dprintf("%s: unhandled pheader type 0x%lx\n", fileName, pheaders[i].p_type); + dprintf("%s: unhandled pheader type 0x%lx\n", fileName, programHeaders[i].p_type); continue; } // we're here, so it must be a PT_LOAD segment - if ((pheaders[i].p_flags & (PF_PROTECTION_MASK)) == (PF_READ | PF_WRITE)) { + if (programHeaders[i].IsReadWrite()) { // this is the writable segment - if (rw_segment_handled) { + if (image->data_region.size != 0) { // we've already created this segment continue; } - rw_segment_handled = true; region = &image->data_region; snprintf(regionName, B_OS_NAME_LENGTH, "%s_data", fileName); - } else if ((pheaders[i].p_flags & (PF_PROTECTION_MASK)) == (PF_READ | PF_EXECUTE)) { + } else if (programHeaders[i].IsExecutable()) { // this is the non-writable segment - if (ro_segment_handled) { + if (image->text_region.size != 0) { // we've already created this segment continue; } - ro_segment_handled = true; region = &image->text_region; snprintf(regionName, B_OS_NAME_LENGTH, "%s_text", fileName); } else { - dprintf("%s: weird program header flags 0x%lx\n", fileName, pheaders[i].p_flags); + dprintf("%s: weird program header flags 0x%lx\n", fileName, + programHeaders[i].p_flags); continue; } - // ToDo: this won't work if the on-disk order of the sections doesn't - // fit the in-memory order... - region->start = start; - region->size = ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); + region->start = (addr_t)reservedAddress + ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); + region->size = ROUNDUP(programHeaders[i].p_memsz + + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE); region->id = create_area(regionName, (void **)®ion->start, B_EXACT_ADDRESS, region->size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); if (region->id < B_OK) { dprintf("%s: error allocating area: %s\n", fileName, strerror(region->id)); - err = B_NOT_AN_EXECUTABLE; + status = B_NOT_AN_EXECUTABLE; goto error4; } - region->delta = region->start - ROUNDOWN(pheaders[i].p_vaddr, B_PAGE_SIZE); - start += region->size; + region->delta = -ROUNDOWN(programHeaders[i].p_vaddr, B_PAGE_SIZE); TRACE(("elf_load_kspace: created area \"%s\" at %p\n", regionName, (void *)region->start)); - len = _kern_read(fd, pheaders[i].p_offset, - (void *)(region->start + (pheaders[i].p_vaddr % B_PAGE_SIZE)), - pheaders[i].p_filesz); - if (len < 0) { - err = len; - dprintf("%s: error reading in seg %d\n", fileName, i); + length = _kern_read(fd, programHeaders[i].p_offset, + (void *)(region->start + (programHeaders[i].p_vaddr % B_PAGE_SIZE)), + programHeaders[i].p_filesz); + if (length < B_OK) { + status = length; + dprintf("%s: error reading in segment %ld\n", fileName, i); goto error5; } } - if (image->data_region.start != 0 - && image->text_region.delta != image->data_region.delta) { - dprintf("%s: deltas do not match!\n", fileName); - dump_image_info(image); - err = B_ERROR; - goto error5; + // 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; } - // modify the dynamic ptr by the delta of the regions - image->dynamic_ptr += image->text_region.delta; + image->data_region.delta += image->data_region.start; + image->text_region.delta += image->text_region.start; - err = elf_parse_dynamic_section(image); - if (err < 0) + // modify the dynamic ptr by the delta of the regions + image->dynamic_section += image->text_region.delta; + +dprintf("loaded: %s\n", path); +dump_image_info(image); + status = elf_parse_dynamic_section(image); + if (status < B_OK) goto error5; - err = elf_relocate(image, ""); - if (err < 0) + status = elf_relocate(image, ""); + if (status < B_OK) goto error5; // We needed to read in the contents of the "text" area, but // now we can protect it read-only/execute set_area_protection(image->text_region.id, B_KERNEL_READ_AREA | B_KERNEL_EXECUTE_AREA); + // There might be a hole between the two segments, and we don't need to + // reserve this any longer + vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress, reservedSize); + // ToDo: this should be enabled by kernel settings! if (1) load_elf_symbol_table(fd, image); - free(pheaders); + free(programHeaders); register_elf_image(image); done: @@ -1407,11 +1427,11 @@ error5: error4: vm_unreserve_address_range(vm_kernel_address_space_id(), reservedAddress, reservedSize); error3: - free(pheaders); + free(programHeaders); error2: free(image); error1: - free(eheader); + free(elfHeader); error: mutex_unlock(&sImageLoadMutex); error0: @@ -1419,7 +1439,7 @@ error0: vfs_put_vnode(vnode); _kern_close(fd); - return err; + return status; }