aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Bucur <stefanb@zytor.com>2008-06-10 18:36:17 +0300
committerStefan Bucur <stefan@stefan-ubumac.(none)>2009-03-15 10:02:13 +0200
commitd804c15789ed7cb2a01e675511499d99cf2f7dd9 (patch)
tree8dea601fbc9ee946368de31bf6fe56729e028292
parentd5e0a99049307507180daaebcef007f39735d9f0 (diff)
downloadsyslinux-elf-d804c15789ed7cb2a01e675511499d99cf2f7dd9.tar.gz
syslinux-elf-d804c15789ed7cb2a01e675511499d99cf2f7dd9.tar.xz
syslinux-elf-d804c15789ed7cb2a01e675511499d99cf2f7dd9.zip
Implemented logic for segment loading.
-rw-r--r--elf/elf_module.c138
-rw-r--r--elf/elf_module.h6
-rw-r--r--elf/elf_utils.h26
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_*/