diff options
Diffstat (limited to 'com32/elflink/elf_module.c')
-rw-r--r-- | com32/elflink/elf_module.c | 1076 |
1 files changed, 0 insertions, 1076 deletions
diff --git a/com32/elflink/elf_module.c b/com32/elflink/elf_module.c deleted file mode 100644 index 64c7b977..00000000 --- a/com32/elflink/elf_module.c +++ /dev/null @@ -1,1076 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <elf.h> - -#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); - -#ifdef ELF_DEBUG -#define DBG_PRINT(fmt, args...) fprintf(stderr, "[DBG] " fmt, ##args) -#else -#define DBG_PRINT(fmt, args...) // Expand to nothing -#endif - - -// User-space debugging routines -#ifdef ELF_DEBUG -static void print_elf_ehdr(Elf32_Ehdr *ehdr) { - int i; - - fprintf(stderr, "Identification:\t"); - for (i=0; i < EI_NIDENT; i++) { - printf("%d ", ehdr->e_ident[i]); - } - fprintf(stderr, "\n"); - fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type); - fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine); - fprintf(stderr, "Version:\t%u\n", ehdr->e_version); - fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry); - fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff); - fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff); - fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags); - fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize, - sizeof(Elf32_Ehdr)); -} - -static void print_elf_symbols(struct elf_module *module) { - unsigned int i; - Elf32_Sym *crt_sym; - - for (i = 1; i < module->symtable_size; i++) { - crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size); - - fprintf(stderr, "%s\n", module->str_table + crt_sym->st_name); - - } -} -#endif //ELF_DEBUG - -static int image_load(struct elf_module *module) { - module->_file = fopen(module->name, "rb"); - - if (module->_file == NULL) { - DBG_PRINT("Could not open object file '%s'\n", module->name); - goto error; - } - - module->_cr_offset = 0; - - return 0; - -error: - if (module->_file != NULL) { - fclose(module->_file); - module->_file = NULL; - } - - return -1; -} - - -static int image_unload(struct elf_module *module) { - if (module->_file != NULL) { - fclose(module->_file); - module->_file = NULL; - } - module->_cr_offset = 0; - - return 0; -} - -static int image_read(void *buff, size_t size, struct elf_module *module) { - size_t result = fread(buff, size, 1, module->_file); - - if (result < 1) - return -1; - - DBG_PRINT("[I/O] Read %u\n", size); - module->_cr_offset += size; - return 0; -} - -static int image_skip(size_t size, struct elf_module *module) { - void *skip_buff = NULL; - size_t result; - - if (size == 0) - return 0; - - skip_buff = malloc(size); - result = fread(skip_buff, size, 1, module->_file); - free(skip_buff); - - if (result < 1) - return -1; - - DBG_PRINT("[I/O] Skipped %u\n", size); - module->_cr_offset += size; - return 0; -} - -static int image_seek(Elf32_Off offset, struct elf_module *module) { - if (offset < module->_cr_offset) // Cannot seek backwards - return -1; - - return image_skip(offset - module->_cr_offset, module); -} - - -// Initialization of the module subsystem -int modules_init(void) { - return 0; -} - -// Termination of the module subsystem -void modules_term(void) { - -} - -// Allocates the structure for a new module -struct elf_module *module_alloc(const char *name) { - struct elf_module *result = malloc(sizeof(struct elf_module)); - - 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_common(Elf32_Ehdr *elf_hdr) { - // Check the header magic - if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 || - elf_hdr->e_ident[EI_MAG1] != ELFMAG1 || - elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || - elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { - - DBG_PRINT("The file is not an ELF object\n"); - return -1; - } - - if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) { - DBG_PRINT("Invalid ELF class code\n"); - return -1; - } - - if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) { - DBG_PRINT("Invalid ELF data encoding\n"); - return -1; - } - - if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION || - elf_hdr->e_version != MODULE_ELF_VERSION) { - DBG_PRINT("Invalid ELF file version\n"); - return -1; - } - - if (elf_hdr->e_machine != MODULE_ELF_MACHINE) { - DBG_PRINT("Invalid ELF architecture\n"); - return -1; - } - - return 0; -} - -static int check_header(Elf32_Ehdr *elf_hdr) { - int res; - - res = check_header_common(elf_hdr); - - if (res != 0) - return res; - - if (elf_hdr->e_type != MODULE_ELF_TYPE) { - DBG_PRINT("The ELF file must be a shared object\n"); - return -1; - } - - if (elf_hdr->e_phoff == 0x00000000) { - DBG_PRINT("PHT missing\n"); - return -1; - } - - return 0; -} - -static int check_header_shallow(Elf32_Ehdr *elf_hdr) { - int res; - - res = check_header_common(elf_hdr); - - if (res != 0) - return res; - - if (elf_hdr->e_shoff == 0x00000000) { - DBG_PRINT("SHT missing\n"); - return -1; - } - - return 0; -} -/* - * - * The implementation assumes that the loadable segments are present - * in the PHT sorted by their offsets, so that only forward seeks would - * be necessary. - */ -static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { - int i; - int res = 0; - void *pht = NULL; - 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 - - Elf32_Addr dyn_addr = 0x00000000; - - // Get to the PHT - image_seek(elf_hdr->e_phoff, module); - - // Load the PHT - pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize); - image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module); - - // Compute the memory needings of the module - for (i=0; i < elf_hdr->e_phnum; i++) { - cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); - - switch (cr_pht->p_type) { - case 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); - break; - case PT_DYNAMIC: - dyn_addr = cr_pht->p_vaddr; - break; - default: - // Unsupported - ignore - break; - } - } - - if (max_addr - min_addr == 0) { - // No loadable segments - DBG_PRINT("No loadable segments found\n"); - goto out; - } - - if (dyn_addr == 0) { - DBG_PRINT("No dynamic information segment found\n"); - goto out; - } - - // 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 (elf_malloc(&module->module_addr, - max_align, - max_alloc-min_alloc) != 0) { - - DBG_PRINT("Could not allocate segments\n"); - goto out; - } - - 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 = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); - - if (cr_pht->p_type == PT_LOAD) { - // Copy the segment at its destination - if (cr_pht->p_offset < module->_cr_offset) { - // The segment contains data before the current offset - // It can be discarded without worry - it would contain only - // headers - Elf32_Off aux_off = module->_cr_offset - cr_pht->p_offset; - - if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off, - cr_pht->p_filesz - aux_off, module) < 0) { - res = -1; - goto out; - } - } else { - if (image_seek(cr_pht->p_offset, module) < 0) { - res = -1; - goto out; - } - - if (image_read(module_get_absolute(cr_pht->p_vaddr, module), - cr_pht->p_filesz, module) < 0) { - res = -1; - goto out; - } - } - - DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", - cr_pht->p_filesz, - cr_pht->p_vaddr, - (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module)); - } - } - - // Setup dynamic segment location - module->dyn_table = module_get_absolute(dyn_addr, module); - - DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, - max_align); - DBG_PRINT("Module size: 0x%08x\n", module->module_size); - -out: - // Free up allocated memory - if (pht != NULL) - free(pht); - - return res; -} - -static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) { - int i; - int res = 0; - void *sht = NULL; - void *buffer = NULL; - Elf32_Shdr *crt_sht; - Elf32_Off buff_offset; - - Elf32_Off min_offset = 0xFFFFFFFF; - Elf32_Off max_offset = 0x00000000; - Elf32_Word max_align = 0x1; - - Elf32_Off sym_offset = 0xFFFFFFFF; - Elf32_Off str_offset = 0xFFFFFFFF; - - - char *sh_strtable; - - // We buffer the data up to the SHT - buff_offset = module->_cr_offset; - - buffer = malloc(elf_hdr->e_shoff - buff_offset); - // Get to the SHT - image_read(buffer, elf_hdr->e_shoff - buff_offset, module); - - // Load the SHT - sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); - image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); - - // Get the string table of the section names - crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize); - sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset)); - - for (i = 0; i < elf_hdr->e_shnum; i++) { - crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize); - - if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) { - // We found the symbol table - min_offset = MIN(min_offset, crt_sht->sh_offset); - max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); - max_align = MAX(max_align, crt_sht->sh_addralign); - - sym_offset = crt_sht->sh_offset; - - module->syment_size = crt_sht->sh_entsize; - module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize; - } - if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) { - // We found the string table - min_offset = MIN(min_offset, crt_sht->sh_offset); - max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); - max_align = MAX(max_align, crt_sht->sh_addralign); - - str_offset = crt_sht->sh_offset; - - module->strtable_size = crt_sht->sh_size; - } - } - - if (elf_malloc(&module->module_addr, max_align, - max_offset - min_offset) != 0) { - DBG_PRINT("Could not allocate sections\n"); - goto out; - } - - // Copy the data - image_seek(min_offset, module); - image_read(module->module_addr, max_offset - min_offset, module); - - // Setup module information - module->module_size = max_offset - min_offset; - module->str_table = (char*)(module->module_addr + (str_offset - min_offset)); - module->sym_table = module->module_addr + (sym_offset - min_offset); - -out: - // Release the SHT - if (sht != NULL) - free(sht); - - // Release the buffer - if (buffer != NULL) - free(buffer); - - return res; -} - -static int prepare_dynlinking(struct elf_module *module) { - Elf32_Dyn *dyn_entry = module->dyn_table; - - while (dyn_entry->d_tag != DT_NULL) { - switch (dyn_entry->d_tag) { - case DT_NEEDED: - // TODO: Manage dependencies here - break; - case DT_HASH: - module->hash_table = - (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - case DT_GNU_HASH: - module->ghash_table = - (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - case DT_STRTAB: - module->str_table = - (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - case DT_SYMTAB: - module->sym_table = - module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - case DT_STRSZ: - module->strtable_size = dyn_entry->d_un.d_val; - break; - case DT_SYMENT: - module->syment_size = dyn_entry->d_un.d_val; - break; - case DT_PLTGOT: // The first entry in the GOT - module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - } - - dyn_entry++; - } - - // Now compute the number of symbols in the symbol table - if (module->ghash_table != NULL) { - module->symtable_size = module->ghash_table[1]; - } else { - module->symtable_size = module->hash_table[1]; - } - - 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); - - // The symbol reference index - Elf32_Word sym = ELF32_R_SYM(rel->r_info); - unsigned char type = ELF32_R_TYPE(rel->r_info); - - // The symbol definition (if applicable) - Elf32_Sym *sym_def = NULL; - struct elf_module *sym_module = NULL; - Elf32_Addr sym_addr = 0x0; - - if (sym > 0) { - // Find out details about the symbol - - // The symbol reference - Elf32_Sym *sym_ref = - (Elf32_Sym*)(module->sym_table + sym * module->syment_size); - - // The symbol definition - sym_def = - global_find_symbol(module->str_table + sym_ref->st_name, - &sym_module); - - if (sym_def == NULL) { - // This should never happen - DBG_PRINT("Cannot perform relocation for symbol %s\n", - module->str_table + sym_ref->st_name); - - return -1; - } - - // 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) { - case R_386_NONE: - // Do nothing - break; - case R_386_32: - *dest += sym_addr; - break; - case R_386_PC32: - *dest += sym_addr - (Elf32_Addr)dest; - break; - case R_386_COPY: - if (sym_addr > 0) { - memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); - } - break; - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - // Maybe TODO: Keep track of the GOT entries allocations - *dest = sym_addr; - break; - case R_386_RELATIVE: - *dest += module->base_addr; - break; - default: - DBG_PRINT("Relocation type %d not supported\n", type); - return -1; - } - - return 0; -} - -static int resolve_symbols(struct elf_module *module) { - Elf32_Dyn *dyn_entry = module->dyn_table; - unsigned int i; - int res; - - Elf32_Word plt_rel_size = 0; - void *plt_rel = NULL; - - void *rel = NULL; - Elf32_Word rel_size = 0; - Elf32_Word rel_entry = 0; - - // The current relocation - Elf32_Rel *crt_rel; - - while (dyn_entry->d_tag != DT_NULL) { - switch(dyn_entry->d_tag) { - - // PLT relocation information - case DT_PLTRELSZ: - plt_rel_size = dyn_entry->d_un.d_val; - break; - case DT_PLTREL: - if (dyn_entry->d_un.d_val != DT_REL) { - DBG_PRINT("Unsupported PLT relocation\n"); - return -1; - } - case DT_JMPREL: - plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - - // Standard relocation information - case DT_REL: - rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); - break; - case DT_RELSZ: - rel_size = dyn_entry->d_un.d_val; - break; - case DT_RELENT: - rel_entry = dyn_entry->d_un.d_val; - break; - - // Module initialization and termination - case DT_INIT: - // TODO Implement initialization functions - break; - case DT_FINI: - // TODO Implement finalization functions - break; - } - - dyn_entry++; - } - - if (rel_size > 0) { - // Process standard relocations - for (i = 0; i < rel_size/rel_entry; i++) { - crt_rel = (Elf32_Rel*)(rel + i*rel_entry); - - res = perform_relocation(module, crt_rel); - - if (res < 0) - return res; - } - - } - - if (plt_rel_size > 0) { - // TODO: Permit this lazily - // Process PLT relocations - for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) { - crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel)); - - res = perform_relocation(module, crt_rel); - - if (res < 0) - return res; - } - } - - return 0; -} - -static int check_symbols(struct elf_module *module) { - unsigned int i; - Elf32_Sym *crt_sym = NULL, *ref_sym = NULL; - char *crt_name; - struct elf_module *crt_module; - - int strong_count; - int weak_count; - - for (i = 1; i < module->symtable_size; i++) { - crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size); - crt_name = module->str_table + crt_sym->st_name; - - strong_count = 0; - weak_count = 0; - - list_for_each_entry(crt_module, &modules, list) { - ref_sym = module_find_symbol(crt_name, crt_module); - - // If we found a definition for our symbol... - if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF) { - switch (ELF32_ST_BIND(ref_sym->st_info)) { - case STB_GLOBAL: - strong_count++; - break; - case STB_WEAK: - weak_count++; - break; - } - } - } - - if (crt_sym->st_shndx == SHN_UNDEF) { - // We have an undefined symbol - if (strong_count == 0 && weak_count == 0) { - DBG_PRINT("Symbol %s is undefined\n", crt_name); - return -1; - } - } else { - if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL) { - // It's not an error - at relocation, the most recent symbol - // will be considered - DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name); - } - } - } - - return 0; -} - -static int extract_operations(struct elf_module *module) { - Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module); - Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module); - - if (init_sym == NULL) { - DBG_PRINT("Cannot find initialization routine.\n"); - return -1; - } - if (exit_sym == NULL) { - DBG_PRINT("Cannot find exit routine.\n"); - return -1; - } - - module->init_func = (module_init_func*)module_get_absolute( - init_sym->st_value, module); - - module->exit_func = (module_exit_func*)module_get_absolute( - exit_sym->st_value, module); - - return 0; -} - -// Loads the module into the system -int module_load(struct elf_module *module) { - int res; - Elf32_Ehdr elf_hdr; - - // Get a mapping/copy of the ELF file in memory - res = image_load(module); - - if (res < 0) { - return res; - } - - // The module is a fully featured dynamic library - module->shallow = 0; - - CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error); - - // Checking the header signature and members - CHECKED(res, check_header(&elf_hdr), error); - - // Load the segments in the memory - CHECKED(res, load_segments(module, &elf_hdr), error); - // Obtain dynamic linking information - CHECKED(res, prepare_dynlinking(module), error); - - // Check the symbols for duplicates / missing definitions - CHECKED(res, check_symbols(module), error); - - // Obtain constructors and destructors - CHECKED(res, extract_operations(module), error); - - // Add the module at the beginning of the module list - list_add(&module->list, &modules); - - // Perform the relocations - resolve_symbols(module); - - - - // The file image is no longer needed - image_unload(module); - - DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (init@0x%08X, exit@0x%08X)\n", - module->name, *(module->init_func), *(module->exit_func)); - - return 0; - -error: - // Remove the module from the module list (if applicable) - list_del_init(&module->list); - - if (module->module_addr != NULL) { - elf_free(module->module_addr); - module->module_addr = NULL; - } - - image_unload(module); - - return res; -} - -int module_load_shallow(struct elf_module *module) { - int res; - Elf32_Ehdr elf_hdr; - - res = image_load(module); - - if (res < 0) - return res; - - module->shallow = 1; - - CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error); - - // Checking the header signature and members - CHECKED(res, check_header_shallow(&elf_hdr), error); - - CHECKED(res, load_shallow_sections(module, &elf_hdr), error); - - // Check the symbols for duplicates / missing definitions - CHECKED(res, check_symbols(module), error); - - // Add the module at the beginning of the module list - list_add(&module->list, &modules); - - // The file image is no longer needed - image_unload(module); - - DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name); - - return 0; - -error: - image_unload(module); - - return res; -} - -// 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)) { - DBG_PRINT("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 or sections - elf_free(module->module_addr); - - DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "", - module->name); - // Release the module structure - free(module); - - return 0; -} - - -static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) { - unsigned long h = elf_hash((const unsigned char*)name); - Elf32_Word *cr_word = module->hash_table; - - Elf32_Word nbucket = *cr_word++; - cr_word++; // Skip nchain - - Elf32_Word *bkt = cr_word; - Elf32_Word *chn = cr_word + nbucket; - - Elf32_Word crt_index = bkt[h % module->hash_table[0]]; - Elf32_Sym *crt_sym; - - - while (crt_index != STN_UNDEF) { - crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size); - - if (strcmp(name, module->str_table + crt_sym->st_name) == 0) - return crt_sym; - - crt_index = chn[crt_index]; - } - - return NULL; -} - -static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) { - unsigned long h = elf_gnu_hash((const unsigned char*)name); - - // Setup code (TODO: Optimize this by computing only once) - Elf32_Word *cr_word = module->ghash_table; - Elf32_Word nbucket = *cr_word++; - Elf32_Word symbias = *cr_word++; - Elf32_Word bitmask_nwords = *cr_word++; - - if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) { - DBG_PRINT("Invalid GNU Hash structure\n"); - return NULL; - } - - Elf32_Word gnu_shift = *cr_word++; - - Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word; - cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords; - - Elf32_Word *gnu_buckets = cr_word; - cr_word += nbucket; - - Elf32_Word *gnu_chain_zero = cr_word - symbias; - - // Computations - Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) & - (bitmask_nwords - 1)]; - - unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1); - unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1); - - if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) { - unsigned long rem; - Elf32_Word bucket; - - rem = h % nbucket; - - bucket = gnu_buckets[rem]; - - if (bucket != 0) { - const Elf32_Word* hasharr = &gnu_chain_zero[bucket]; - - do { - if (((*hasharr ^ h ) >> 1) == 0) { - Elf32_Sym *crt_sym = (Elf32_Sym*)(module->sym_table + - (hasharr - gnu_chain_zero) * module->syment_size); - - if (strcmp(name, module->str_table + crt_sym->st_name) == 0) { - return crt_sym; - } - } - } while ((*hasharr++ & 1u) == 0); - } - } - - return NULL; -} - -static Elf32_Sym *module_find_symbol_iterate(const char *name, - struct elf_module *module) { - - unsigned int i; - Elf32_Sym *crt_sym; - - for (i=1; i < module->symtable_size; i++) { - crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size); - - if (strcmp(name, module->str_table + crt_sym->st_name) == 0) { - return crt_sym; - } - } - - return NULL; -} - -Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) { - Elf32_Sym *result = NULL; - - if (module->ghash_table != NULL) - result = module_find_symbol_gnu(name, module); - - if (result == NULL) { - if (module->hash_table != NULL) - result = module_find_symbol_sysv(name, module); - else - result = module_find_symbol_iterate(name, module); - } - - return result; -} - -Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) { - struct elf_module *crt_module; - Elf32_Sym *crt_sym = NULL; - Elf32_Sym *result = NULL; - - list_for_each_entry(crt_module, &modules, list) { - crt_sym = module_find_symbol(name, crt_module); - - if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) { - switch (ELF32_ST_BIND(crt_sym->st_info)) { - case STB_GLOBAL: - if (module != NULL) { - *module = crt_module; - } - return crt_sym; - case STB_WEAK: - // Consider only the first weak symbol - if (result == NULL) { - if (module != NULL) { - *module = crt_module; - } - result = crt_sym; - } - break; - } - } - } - - return result; -} |