diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/elf_module.c | 139 | ||||
-rw-r--r-- | elf/elf_module.h | 5 | ||||
-rw-r--r-- | elf/elftest.c | 19 |
3 files changed, 143 insertions, 20 deletions
diff --git a/elf/elf_module.c b/elf/elf_module.c index 0cf77452..24137402 100644 --- a/elf/elf_module.c +++ b/elf/elf_module.c @@ -95,7 +95,10 @@ error: static int image_unload(struct elf_module *module) { - fclose(module->_file); + if (module->_file != NULL) { + fclose(module->_file); + module->_file = NULL; + } module->_cr_offset = 0; return 0; @@ -155,11 +158,36 @@ struct elf_module *module_alloc(const char *name) { memset(result, 0, sizeof(struct elf_module)); + INIT_LIST_HEAD(&result->list); + INIT_LIST_HEAD(&result->required); + INIT_LIST_HEAD(&result->dependants); + strncpy(result->name, name, MODULE_NAME_SIZE); return result; } +static struct module_dep *module_dep_alloc(struct elf_module *module) { + struct module_dep *result = malloc(sizeof(struct module_dep)); + + INIT_LIST_HEAD (&result->list); + + result->module = module; + + return result; +} + +struct elf_module *module_find(const char *name) { + struct elf_module *cr_module; + + list_for_each_entry(cr_module, &modules, list) { + if (strcmp(cr_module->name, name) == 0) + return cr_module; + } + + return NULL; +} + // Performs verifications on ELF header to assure that the open file is a // valid SYSLINUX ELF module. static int check_header(Elf32_Ehdr *elf_hdr) { @@ -261,12 +289,12 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { if (max_addr - min_addr == 0) { // No loadable segments fprintf(stderr, "No loadable segments found\n"); - return -1; + goto out; } if (dyn_addr == 0) { fprintf(stderr, "No dynamic information segment found\n"); - return -1; + goto out; } // The minimum address that should be allocated @@ -283,7 +311,7 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { max_alloc-min_alloc) != 0) { fprintf(stderr, "Could not allocate segments\n"); - return -1; + goto out; } module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc; @@ -337,7 +365,8 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { out: // Free up allocated memory - free(pht); + if (pht != NULL) + free(pht); return res; } @@ -384,6 +413,59 @@ static int prepare_dynlinking(struct elf_module *module) { return 0; } +static int enforce_dependency(struct elf_module *req, struct elf_module *dep) { + struct module_dep *crt_dep; + struct module_dep *new_dep; + + list_for_each_entry(crt_dep, &req->dependants, list) { + if (crt_dep->module == dep) { + // The dependency is already enforced + return 0; + } + } + + new_dep = module_dep_alloc(req); + list_add(&new_dep->list, &dep->required); + + new_dep = module_dep_alloc(dep); + list_add(&new_dep->list, &req->dependants); + + return 0; +} + +static int clear_dependency(struct elf_module *req, struct elf_module *dep) { + struct module_dep *crt_dep = NULL; + int found = 0; + + list_for_each_entry(crt_dep, &req->dependants, list) { + if (crt_dep->module == dep) { + found = 1; + break; + } + } + + if (found) { + list_del(&crt_dep->list); + free(crt_dep); + } + + found = 0; + + list_for_each_entry(crt_dep, &dep->required, list) { + if (crt_dep->module == req) { + found = 1; + break; + } + } + + if (found) { + list_del(&crt_dep->list); + free(crt_dep); + } + + return 0; +} + static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { Elf32_Word *dest = module_get_absolute(rel->r_offset, module); @@ -409,14 +491,20 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { &sym_module); if (sym_def == NULL) { - fprintf(stderr, "Cannot perform relocation for symbol %s\n", + // This should never happen + fprintf(stderr, "Warning: Cannot perform relocation for symbol %s\n", module->str_table + sym_ref->st_name); + // TODO: Return an error return 0; } // Compute the absolute symbol virtual address sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module); + if (sym_module != module) { + // Create a dependency + enforce_dependency(sym_module, module); + } } switch (type) { @@ -443,8 +531,8 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { *dest += module->base_addr; break; default: - fprintf(stderr, "Relocation type %d not supported\n", type); - return -1; + fprintf(stderr, "Warning: Relocation type %d not supported\n", type); + break; } return 0; @@ -569,6 +657,7 @@ static int check_symbols(struct elf_module *module) { // We have an undefined symbol if (strong_count == 0 && weak_count == 0) { fprintf(stderr, "Symbol %s is undefined\n", crt_name); + // TODO: Return an error //return -1; } } else { @@ -587,11 +676,6 @@ int module_load(struct elf_module *module) { int res; Elf32_Ehdr elf_hdr; - - INIT_LIST_HEAD(&module->list); - INIT_LIST_HEAD(&module->deps); - - // Get a mapping/copy of the ELF file in memory res = image_load(module); @@ -622,15 +706,23 @@ int module_load(struct elf_module *module) { list_add(&module->list, &modules); // Perform the relocations - CHECKED(res, resolve_symbols(module), error); + resolve_symbols(module); // The file image is no longer needed - CHECKED(res, image_unload(module), error); + image_unload(module); return 0; error: + // Remove the module from the module list (if applicable) + list_del_init(&module->list); + + if (module->module_addr != NULL) { + free(module->module_addr); + module->module_addr = NULL; + } + image_unload(module); return res; @@ -638,7 +730,24 @@ error: // Unloads the module from the system and releases all the associated memory int module_unload(struct elf_module *module) { + struct module_dep *crt_dep, *tmp; + // Make sure nobody needs us + if (!list_empty(&module->dependants)) { + fprintf(stderr, "Module is required by other modules.\n"); + return -1; + } + + // Remove any dependency information + list_for_each_entry_safe(crt_dep, tmp, &module->required, list) { + clear_dependency(crt_dep->module, module); + } + + // Remove the module from the module list + list_del_init(&module->list); + // Release the loaded segments + free(module->module_addr); + // Release the module structure free(module); return 0; diff --git a/elf/elf_module.h b/elf/elf_module.h index 856717f7..1454ee71 100644 --- a/elf/elf_module.h +++ b/elf/elf_module.h @@ -23,7 +23,8 @@ typedef void (*module_exit_func)(); struct elf_module { char name[MODULE_NAME_SIZE]; // The module name - struct list_head deps; // Head of module dependency list + struct list_head required; // Head of the required modules list + struct list_head dependants; // Head of module dependants list struct list_head list; // The list entry in the module list module_init_func init_func; // The initialization entry point @@ -71,6 +72,8 @@ extern int module_load(struct elf_module *module); // Unloads the module from the system and releases all the associated memory extern int module_unload(struct elf_module *module); +extern struct elf_module *module_find(const char *name); + extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module); extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module); diff --git a/elf/elftest.c b/elf/elftest.c index 7013938e..0a38bbe6 100644 --- a/elf/elftest.c +++ b/elf/elftest.c @@ -37,6 +37,7 @@ void test_hello() { int main(int argc, char **argv) { int res; + int i; struct elf_module *module; const char *module_name = NULL; @@ -56,8 +57,8 @@ int main(int argc, char **argv) { exit(1); } - while (argc > 0) { - module_name = argv[0]; + for (i=0; i < argc; i++){ + module_name = argv[i]; module = module_alloc(module_name); @@ -73,12 +74,22 @@ int main(int argc, char **argv) { goto error; } - argc--; - argv++; } test_hello(); + for (i=argc-1; i >= 0; i--) { + module_name = argv[i]; + module = module_find(module_name); + + res = module_unload(module); + + if (res < 0) { + fprintf(stderr, "Could not unload the module\n"); + goto error; + } + } + modules_term(); return 0; |