diff options
author | Stefan Bucur <stefanb@zytor.com> | 2008-06-10 18:36:17 +0300 |
---|---|---|
committer | Stefan Bucur <stefanb@zytor.com> | 2008-06-10 18:36:17 +0300 |
commit | 4e14b7d997d8602ce241f015754104d31ced73de (patch) | |
tree | 5e6985661ceb9fc38c86b472ae243134347629f8 | |
parent | e4642a4d0fac67f22e2e63cbcaea915c507e241e (diff) | |
download | syslinux-elf-4e14b7d997d8602ce241f015754104d31ced73de.tar.gz syslinux-elf-4e14b7d997d8602ce241f015754104d31ced73de.tar.xz syslinux-elf-4e14b7d997d8602ce241f015754104d31ced73de.zip |
Implemented logic for segment loading.
-rw-r--r-- | elf/elf_module.c | 138 | ||||
-rw-r--r-- | elf/elf_module.h | 6 | ||||
-rw-r--r-- | elf/elf_utils.h | 26 |
3 files changed, 156 insertions, 14 deletions
diff --git a/elf/elf_module.c b/elf/elf_module.c index de5a311a..c89972e6 100644 --- a/elf/elf_module.c +++ b/elf/elf_module.c @@ -15,7 +15,18 @@ #include "linux_list.h" #include "elf_module.h" +#include "elf_utils.h" +// Performs an operation and jumps to a given label if an error occurs +#define CHECKED(res, expr, error) \ + do { \ + (res) = (expr); \ + if ((res) < 0) \ + goto error; \ + } while (0) + +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) // The list of loaded modules static LIST_HEAD(modules); @@ -134,7 +145,10 @@ struct elf_module *module_alloc(const char *name) { return result; } -static int check_header(Elf32_Ehdr *elf_hdr) { +// Performs verifications on ELF header to assure that the open file is a +// valid SYSLINUX ELF module. +static int check_header(struct elf_module *module) { + Elf32_Ehdr *elf_hdr = elf_get_header(module->file_image); // Check the header magic if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 || @@ -142,7 +156,7 @@ static int check_header(Elf32_Ehdr *elf_hdr) { elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { - fprintf(stderr, "Invalid ELF magic\n"); + fprintf(stderr, "The file is not an ELF object\n"); return -1; } @@ -156,11 +170,107 @@ static int check_header(Elf32_Ehdr *elf_hdr) { return -1; } - if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION) { + if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION || + elf_hdr->e_version != MODULE_ELF_VERSION) { fprintf(stderr, "Invalid ELF file version\n"); return -1; } + if (elf_hdr->e_type != MODULE_ELF_TYPE) { + fprintf(stderr, "The ELF file must be a shared object\n"); + return -1; + } + + + if (elf_hdr->e_machine != MODULE_ELF_MACHINE) { + fprintf(stderr, "Invalid ELF architecture\n"); + return -1; + } + + if (elf_hdr->e_phoff == 0x00000000) { + fprintf(stderr, "PHT missing\n"); + return -1; + } + + return 0; +} + +static int load_segments(struct elf_module *module) { + int i; + Elf32_Ehdr *elf_hdr = elf_get_header(module->file_image); + Elf32_Phdr *cr_pht; + + Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr + Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr + Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign() + Elf32_Addr min_alloc, max_alloc; // Min. and max. aligned allocables + + + // Compute the memory needings of the module + for (i=0; i < elf_hdr->e_phnum; i++) { + cr_pht = elf_get_ph(module->file_image, i); + + if (cr_pht->p_type == PT_LOAD) { + if (i == 0) { + min_addr = cr_pht->p_vaddr; + } else { + min_addr = MIN(min_addr, cr_pht->p_vaddr); + } + + max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz); + max_align = MAX(max_align, cr_pht->p_align); + } + } + + if (max_addr - min_addr == 0) { + // No loadable segments + fprintf(stderr, "No loadable segments found\n"); + return -1; + } + + // The minimum address that should be allocated + min_alloc = min_addr - (min_addr % max_align); + + // The maximum address that should be allocated + max_alloc = max_addr - (max_addr % max_align); + if (max_addr % max_align > 0) + max_alloc += max_align; + + + if (posix_memalign(&module->module_addr, + max_align, + max_alloc-min_alloc) != 0) { + + fprintf(stderr, "Could not allocate segments\n"); + return -1; + } + + module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc; + module->module_size = max_alloc - min_alloc; + + // Zero-initialize the memory + memset(module->module_addr, 0, module->module_size); + + for (i = 0; i < elf_hdr->e_phnum; i++) { + cr_pht = elf_get_ph(module->file_image, i); + + if (cr_pht->p_type == PT_LOAD) { + // Copy the segment at its destination + memcpy((void*)(module->base_addr + cr_pht->p_vaddr), + module->file_image + cr_pht->p_offset, + cr_pht->p_filesz); + + printf("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", + cr_pht->p_filesz, + cr_pht->p_vaddr, + module->base_addr + cr_pht->p_vaddr); + } + } + + printf("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, + max_align); + printf("Module size: 0x%08x\n", module->module_size); + return 0; } @@ -172,27 +282,27 @@ int module_load(struct elf_module *module) { INIT_LIST_HEAD(&module->list); INIT_LIST_HEAD(&module->deps); + + // Get a mapping/copy of the ELF file in memory res = load_image(module); if (res < 0) { return res; } - elf_hdr = (Elf32_Ehdr*)module->file_image; - - res = check_header(elf_hdr); - - if (res < 0) { - goto error; - } + // Checking the header signature and members + CHECKED(res, check_header(module), error); + // Obtain the ELF header + elf_hdr = elf_get_header(module->file_image); + + // DEBUG print_elf_ehdr(elf_hdr); - res = unload_image(module); + CHECKED(res, load_segments(module), error); - if (res < 0) { - return res; - } + // The file image is no longer neededchar + CHECKED(res, unload_image(module), error); return 0; diff --git a/elf/elf_module.h b/elf/elf_module.h index fd0e15c5..6074b559 100644 --- a/elf/elf_module.h +++ b/elf/elf_module.h @@ -10,6 +10,8 @@ #define MODULE_ELF_CLASS ELFCLASS32 #define MODULE_ELF_DATA ELFDATA2LSB #define MODULE_ELF_VERSION EV_CURRENT +#define MODULE_ELF_TYPE ET_DYN +#define MODULE_ELF_MACHINE EM_386 typedef int (*module_init_func)(); @@ -28,6 +30,10 @@ struct elf_module { void *file_image; // The image of the module file in memory uint32_t file_size; // The size of the module file + void *module_addr; // The module location in the memory + Elf32_Addr base_addr; // The base address of the module + Elf32_Word module_size; // The module size in memory + // Information for modules loaded in user space #ifdef ELF_USERSPACE_TEST int file_fd; // The file descriptor of the open file diff --git a/elf/elf_utils.h b/elf/elf_utils.h new file mode 100644 index 00000000..5e7387f3 --- /dev/null +++ b/elf/elf_utils.h @@ -0,0 +1,26 @@ +#ifndef ELF_UTILS_H_ +#define ELF_UTILS_H_ + +#include <elf.h> + +// Returns a pointer to the ELF header structure +static inline Elf32_Ehdr *elf_get_header(void *elf_image) { + return (Elf32_Ehdr*)elf_image; +} + +// Returns a pointer to the first entry in the Program Header Table +static inline Elf32_Phdr *elf_get_pht(void *elf_image) { + Elf32_Ehdr *elf_hdr = elf_get_header(elf_image); + + return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff); +} + +// Returns the element with the given index in the PTH +static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) { + Elf32_Phdr *elf_pht = elf_get_pht(elf_image); + Elf32_Ehdr *elf_hdr = elf_get_header(elf_image); + + return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize); +} + +#endif /*ELF_UTILS_H_*/ |