From fac2992f2848ce2a630ba03f3a9f43d5928297ae Mon Sep 17 00:00:00 2001 From: Stefan Bucur Date: Mon, 11 Aug 2008 16:48:30 +0300 Subject: Reorganized the module system in a consistent API. --- com32/elflink/Makefile | 7 +- com32/elflink/elf_module.c | 1076 --------------------------------- com32/elflink/elf_module.h | 250 -------- com32/elflink/elf_utils.c | 89 --- com32/elflink/elf_utils.h | 33 - com32/elflink/linux_list.h | 463 -------------- com32/elflink/modules/Makefile | 2 +- com32/elflink/modules/hello.c | 11 +- com32/elflink/test_com32.c | 2 +- com32/include/klibc/compiler.h | 3 + com32/include/linux/list.h | 463 ++++++++++++++ com32/include/sys/elfutils.h | 33 + com32/include/sys/module.h | 286 +++++++++ com32/lib/Makefile | 7 +- com32/lib/sys/module/common.c | 497 +++++++++++++++ com32/lib/sys/module/common.h | 70 +++ com32/lib/sys/module/elf_module.c | 465 ++++++++++++++ com32/lib/sys/module/elfutils.c | 89 +++ com32/lib/sys/module/shallow_module.c | 152 +++++ 19 files changed, 2069 insertions(+), 1929 deletions(-) delete mode 100644 com32/elflink/elf_module.c delete mode 100644 com32/elflink/elf_module.h delete mode 100644 com32/elflink/elf_utils.c delete mode 100644 com32/elflink/elf_utils.h delete mode 100644 com32/elflink/linux_list.h create mode 100644 com32/include/linux/list.h create mode 100644 com32/include/sys/elfutils.h create mode 100644 com32/include/sys/module.h create mode 100644 com32/lib/sys/module/common.c create mode 100644 com32/lib/sys/module/common.h create mode 100644 com32/lib/sys/module/elf_module.c create mode 100644 com32/lib/sys/module/elfutils.c create mode 100644 com32/lib/sys/module/shallow_module.c diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile index bf50a2eb..5691d66e 100644 --- a/com32/elflink/Makefile +++ b/com32/elflink/Makefile @@ -10,9 +10,6 @@ ## ## ----------------------------------------------------------------------- -## -## COM32 standard modules -## TMPFILE = $(shell mktemp /tmp/gcc_ok.XXXXXX) CC = gcc @@ -89,8 +86,8 @@ test_memalign.elf : test_memalign.o $(LIBS) $(LD) $(LDFLAGS) -o $@ $^ test_com32.elf: CFLAGS += -DELF_DEBUG -test_com32.elf: test_com32.o elf_module.o elf_utils.o ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC) - $(LD) -n $(LDFLAGS) -o $@ test_com32.o elf_module.o elf_utils.o ../libutil/libutil_com.a $(LIBGCC) --whole-archive ../lib/libcom32min.a +test_com32.elf: test_com32.o ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC) + $(LD) -n $(LDFLAGS) -o $@ test_com32.o ../libutil/libutil_com.a $(LIBGCC) --whole-archive ../lib/libcom32min.a $(OBJCOPY) --extract-symbol $@ _root_.dyn tidy dist: 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 -#include -#include -#include - -#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; -} diff --git a/com32/elflink/elf_module.h b/com32/elflink/elf_module.h deleted file mode 100644 index ed3e3766..00000000 --- a/com32/elflink/elf_module.h +++ /dev/null @@ -1,250 +0,0 @@ -#ifndef ELF_MODULE_H_ -#define ELF_MODULE_H_ - -#include -#include -#include -#include "linux_list.h" - -/* - * The maximum length of the module file name (including path), stored - * in the struct module descriptor. - */ -#define MODULE_NAME_SIZE 64 - -/* - * Accepted values for various ELF header parameters found in an ELF dynamic - * object. - */ -#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules -#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value -#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess -#define MODULE_ELF_VERSION EV_CURRENT // Object version -#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so) -#define MODULE_ELF_MACHINE EM_386 // Target architecture - -#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name -#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name - -/* - * Initialization and finalization function signatures - */ - -/** - * module_init_func - pointer to a initialization routine - * - * The initialization routine is called after all module constructors were invoked. - * It takes no parameters and returns 0 if the module was initialized successfully, - * or a non-zero value if errors have occurred. - */ -typedef int (*module_init_func)(void); - -/** - * module_exit_func - pointer to a finalization routine - * - * The finalization routine is called before the module destructors are to be invoked. - * It simply executes some cleanup code, without error reporting. - */ -typedef void (*module_exit_func)(void); - - -/** - * struct elf_module - structure encapsulating a module loaded in memory. - * - * Each SYSLINUX ELF module must have an associated struct elf_module descriptor - * that keeps track of memory allocations, symbol information, and various other - * resources needed by the module itself or by other modules that depend on it. - * - * There are two types of modules: - * - regular modules, which are actual memory images of a loaded & linked shared - * object (ELF file). Memory is reserved for the struct elf_module structure itself - * and for the object loadable sections read from the file. - * - shallow modules, which are not associated with an ELF shared object, but contain - * metainformation about a memory region already present and containing the - * actual code and data. One particular usage of shallow modules is to access - * symbol information from the root COM32 module loaded by the SYSLINUX core. - * As their name suggests, memory is reserved only for the elf_module structure - * itself and optionally for a usually small memory region containing metainformation - * (symbol information). - * - * Module descriptors are related to each other through dependency information. A module - * can depend on symbols from other modules, and in turn it can provide symbols used - * by other dependant modules. This relationship can be described as a directed - * acyclic graph (DAG). The graph is stored using double linked lists of - * predecessors and successors. There is also a global linked list containing all - * the modules currently loaded. - */ -struct elf_module { - char name[MODULE_NAME_SIZE]; // The module name - - int shallow; // Whether the module contains any code - - 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 - module_exit_func *exit_func; // The module finalization code - - - 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 - - Elf32_Word *hash_table; // The symbol hash table - Elf32_Word *ghash_table; // The GNU style hash table - char *str_table; // The string table - void *sym_table; // The symbol table - void *got; // The Global Offset Table - Elf32_Dyn *dyn_table; // Dynamic loading information table - - Elf32_Word strtable_size; // The size of the string table - Elf32_Word syment_size; // The size of a symbol entry - Elf32_Word symtable_size; // The size of the symbol table - - - // Transient - Data available while the module is loading - FILE *_file; // The file object of the open file - Elf32_Off _cr_offset; // The current offset in the open file -}; - -/** - * struct module_dep - structure encapsulating a module dependency need - * - * This structure represents an item in a double linked list of predecessors or - * successors. The item contents is a pointer to the corresponding module descriptor. - */ -struct module_dep { - struct list_head list; // The list entry in the dependency list - - struct elf_module *module; // The target module descriptor -}; - -/** - * modules_init - initialize the module subsystem. - * - * This function must be called before any module operation is to be performed. - */ -extern int modules_init(void); - - -/** - * modules_term - releases all resources pertaining to the module subsystem. - * - * This function should be called after all module operations. - */ -extern void modules_term(void); - - -/** - * module_alloc - reserves space for a new module descriptor. - * @name: the file name of the module to be loaded. - * - * The function simply allocates a new module descriptor and initializes its fields - * in order to be used by subsequent loading operations. - */ -extern struct elf_module *module_alloc(const char *name); - - -/** - * module_load - loads a regular ELF module into memory. - * @module: the module descriptor returned by module_alloc. - * - * The function reads the module file, checks whether the file has a - * valid structure, then loads into memory the code and the data and performs - * any symbol relocations. A module dependency is created automatically when the - * relocated symbol is defined in a different module. - * - * The function returns 0 if the operation is completed successfully, and - * a non-zero value if an error occurs. Possible errors include invalid module - * structure, missing symbol definitions (unsatisfied dependencies) and memory - * allocation issues. - */ -extern int module_load(struct elf_module *module); - - -/** - * module_load_shallow - loads a shallow ELF module into memory. - * @module: the module descriptor returned by module_alloc. - * - * The function reads the module file, checks whether the file has a valid - * structure, then loads into memory the module metadata. The metadata currently - * contains a symbol table that describes code & data allocated by other means. - * Its current use is to describe the root COM32 module to the rest of the - * module subsystem. - */ -extern int module_load_shallow(struct elf_module *module); - -/** - * module_unload - unloads the module from the system. - * @module: the module descriptor structure. - * - * The function checks to see whether the module can be safely removed, then - * it releases all the associated memory. This function can be applied both - * for standard modules and for shallow modules. - * - * A module can be safely removed from the system when no other modules reference - * symbols from it. - */ -extern int module_unload(struct elf_module *module); - -/** - * module_find - searches for a module by its name. - * @name: the name of the module, as it was specified in module_alloc. - * - * The function returns a pointer to the module descriptor, if found, or - * NULL otherwise. - */ -extern struct elf_module *module_find(const char *name); - -/** - * module_find_symbol - searches for a symbol definition in a given module. - * @name: the name of the symbol to be found. - * @module: the module descriptor structure. - * - * The function searches the module symbol table for a symbol matching exactly - * the name provided. The operation uses the following search algorithms, in this - * order: - * - If a GNU hash table is present in the module, it is used to find the symbol. - * - If the symbol cannot be found with the first method (either the hash table - * is not present or the symbol is not found) and if a regular (SysV) hash table - * is present, a search is performed on the SysV hash table. If the symbol is not - * found, NULL is returned. - * - If the second method cannot be applied, a linear search is performed by - * inspecting every symbol in the symbol table. - * - * If the symbol is found, a pointer to its descriptor structure is returned, and - * NULL otherwise. - */ -extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module); - -/** - * global_find_symbol - searches for a symbol definition in the entire module namespace. - * @name: the name of the symbol to be found. - * @module: an optional (may be NULL) pointer to a module descriptor variable that - * will hold the module where the symbol was found. - * - * The function search for the given symbol name in all the modules currently - * loaded in the system, in the reverse module loading order. That is, the most - * recently loaded module is searched first, followed by the previous one, until - * the first loaded module is reached. - * - * If no module contains the symbol, NULL is returned, otherwise the return value is - * a pointer to the symbol descriptor structure. If the module parameter is not NULL, - * it is filled with the address of the module descriptor where the symbol is defined. - */ -extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module); - -/** - * module_get_absolute - converts an memory address relative to a module base address - * to its absolute value in RAM. - * @addr: the relative address to convert. - * @module: the module whose base address is used for the conversion. - * - * The function returns a pointer to the absolute memory address. - */ -static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) { - return (void*)(module->base_addr + addr); -} - -#endif /*ELF_MODULE_H_*/ diff --git a/com32/elflink/elf_utils.c b/com32/elflink/elf_utils.c deleted file mode 100644 index b957b5da..00000000 --- a/com32/elflink/elf_utils.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include - -#include "elf_utils.h" - -unsigned long elf_hash(const unsigned char *name) { - unsigned long h = 0; - unsigned long g; - - while (*name) { - h = (h << 4) + *name++; - if ((g = h & 0xF0000000)) - h ^= g >> 24; - - h &= ~g; - } - - return h; -} - -unsigned long elf_gnu_hash(const unsigned char *name) { - unsigned long h = 5381; - unsigned char c; - - for (c = *name; c != '\0'; c = *++name) { - h = h * 33 + c; - } - - return h & 0xFFFFFFFF; -} - -#ifdef ELF_NO_POSIX_MEMALIGN - -struct memalign_info { - void *start_addr; - char data[0]; -}; - -int elf_malloc(void **memptr, size_t alignment, size_t size) { - void *start_addr = NULL; - struct memalign_info *info; - - if ((alignment & (alignment - 1)) != 0) - return EINVAL; - if (alignment % sizeof(void*) != 0) - alignment = sizeof(void*); - - start_addr = malloc(size + (alignment > sizeof(struct memalign_info) ? - alignment : sizeof(struct memalign_info))); - - if (start_addr == NULL) - return ENOMEM; - - - info = (struct memalign_info*)(start_addr - - ((unsigned long)start_addr % alignment) + - alignment - sizeof(struct memalign_info)); - - info->start_addr = start_addr; - - *memptr = info->data; - - return 0; -} - -void elf_free(void *memptr) { - struct memalign_info *info = (struct memalign_info*)(memptr - - sizeof(struct memalign_info)); - - free(info->start_addr); -} - -#else - -int elf_malloc(void **memptr, size_t alignment, size_t size) { - if ((alignment & (alignment - 1)) != 0) - return EINVAL; - - if (alignment % sizeof(void*) != 0) - alignment = sizeof(void*); - - return posix_memalign(memptr, alignment, size); -} - -void elf_free(void *memptr) { - free(memptr); -} - -#endif //ELF_NO_POSIX_MEMALIGN diff --git a/com32/elflink/elf_utils.h b/com32/elflink/elf_utils.h deleted file mode 100644 index b8df660e..00000000 --- a/com32/elflink/elf_utils.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ELF_UTILS_H_ -#define ELF_UTILS_H_ - -#include -#include - -// 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); -} - -extern unsigned long elf_hash(const unsigned char *name); -extern unsigned long elf_gnu_hash(const unsigned char *name); - -extern int elf_malloc(void **memptr, size_t alignment, size_t size); -extern void elf_free(void *memptr); - -#endif /*ELF_UTILS_H_*/ diff --git a/com32/elflink/linux_list.h b/com32/elflink/linux_list.h deleted file mode 100644 index 3b92e254..00000000 --- a/com32/elflink/linux_list.h +++ /dev/null @@ -1,463 +0,0 @@ -// This list structure implementation is adapted from the list implementation -// on the Linux kernel. - -// Original source: -// http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=blob_plain;f=include/linux/list.h;hb=HEAD - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -#include -#include - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = NULL; - entry->prev = NULL; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - - -#endif diff --git a/com32/elflink/modules/Makefile b/com32/elflink/modules/Makefile index 35958cf6..fc319b03 100644 --- a/com32/elflink/modules/Makefile +++ b/com32/elflink/modules/Makefile @@ -28,7 +28,7 @@ NASM = nasm NASMOPT = -O9999 RANLIB = ranlib CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -march=i386 -Os \ - -fomit-frame-pointer -D__COM32__ \ + -fomit-frame-pointer -D__COM32__ -DDYNAMIC_MODULE \ -nostdinc -iwithprefix include \ -I../../libutil/include -I../../include \ -Wp,-MT,$@,-MD,$(dir $@).$(notdir $@).d diff --git a/com32/elflink/modules/hello.c b/com32/elflink/modules/hello.c index f396c794..d1054a1f 100644 --- a/com32/elflink/modules/hello.c +++ b/com32/elflink/modules/hello.c @@ -4,17 +4,8 @@ */ #include +#include -typedef int (*module_init_t)(void); -typedef void (*module_exit_t)(void); - -#define __used __attribute__((used)) - -#define MODULE_INIT(fn) static module_init_t __module_init \ - __used __attribute__((section(".ctors_module"))) = fn - -#define MODULE_EXIT(fn) static module_exit_t __module_exit \ - __used __attribute__((section(".dtors_module"))) = fn static int hello_init(void) { printf("Hello, world, from 0x%08X!\n", (unsigned int)&hello_init); diff --git a/com32/elflink/test_com32.c b/com32/elflink/test_com32.c index 8404864f..639e0b33 100644 --- a/com32/elflink/test_com32.c +++ b/com32/elflink/test_com32.c @@ -3,7 +3,7 @@ #include #include -#include "elf_module.h" +#include #define KLIBC_NAME "klibc.dyn" #define ROOT_NAME "_root_.dyn" diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h index 6a938278..b5919d67 100644 --- a/com32/include/klibc/compiler.h +++ b/com32/include/klibc/compiler.h @@ -108,6 +108,9 @@ # define __unusedfunc #endif +/* Used symbol */ +#define __used __attribute__((used)) + /* Constructors and destructors */ #define __constructor __attribute__((constructor)) #define __destructor __attribute__((destructor)) diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h new file mode 100644 index 00000000..3b92e254 --- /dev/null +++ b/com32/include/linux/list.h @@ -0,0 +1,463 @@ +// This list structure implementation is adapted from the list implementation +// on the Linux kernel. + +// Original source: +// http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=blob_plain;f=include/linux/list.h;hb=HEAD + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#include +#include + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + + +#endif diff --git a/com32/include/sys/elfutils.h b/com32/include/sys/elfutils.h new file mode 100644 index 00000000..b8df660e --- /dev/null +++ b/com32/include/sys/elfutils.h @@ -0,0 +1,33 @@ +#ifndef ELF_UTILS_H_ +#define ELF_UTILS_H_ + +#include +#include + +// 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); +} + +extern unsigned long elf_hash(const unsigned char *name); +extern unsigned long elf_gnu_hash(const unsigned char *name); + +extern int elf_malloc(void **memptr, size_t alignment, size_t size); +extern void elf_free(void *memptr); + +#endif /*ELF_UTILS_H_*/ diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h new file mode 100644 index 00000000..fc712695 --- /dev/null +++ b/com32/include/sys/module.h @@ -0,0 +1,286 @@ +/** + * syslinux/module.h + * + * Dynamic ELF modules definitions and services. + */ + + +#ifndef MODULE_H_ +#define MODULE_H_ + +#include +#include +#include +#include + + +/* + * The maximum length of the module file name (including path), stored + * in the struct module descriptor. + */ +#define MODULE_NAME_SIZE 64 + +/* + * Initialization and finalization function signatures + */ + + +/** + * module_init_t - pointer to a initialization routine + * + * The initialization routine is called after all module constructors were invoked. + * It takes no parameters and returns 0 if the module was initialized successfully, + * or a non-zero value if errors have occurred. + */ +typedef int (*module_init_t)(void); + +/** + * module_exit_t - pointer to a finalization routine + * + * The finalization routine is called before the module destructors are to be invoked. + * It simply executes some cleanup code, without error reporting. + */ +typedef void (*module_exit_t)(void); + + +/** + * struct elf_module - structure encapsulating a module loaded in memory. + * + * Each SYSLINUX ELF module must have an associated struct elf_module descriptor + * that keeps track of memory allocations, symbol information, and various other + * resources needed by the module itself or by other modules that depend on it. + * + * There are two types of modules: + * - regular modules, which are actual memory images of a loaded & linked shared + * object (ELF file). Memory is reserved for the struct elf_module structure itself + * and for the object loadable sections read from the file. + * - shallow modules, which are not associated with an ELF shared object, but contain + * metainformation about a memory region already present and containing the + * actual code and data. One particular usage of shallow modules is to access + * symbol information from the root COM32 module loaded by the SYSLINUX core. + * As their name suggests, memory is reserved only for the elf_module structure + * itself and optionally for a usually small memory region containing metainformation + * (symbol information). + * + * Module descriptors are related to each other through dependency information. A module + * can depend on symbols from other modules, and in turn it can provide symbols used + * by other dependant modules. This relationship can be described as a directed + * acyclic graph (DAG). The graph is stored using double linked lists of + * predecessors and successors. There is also a global linked list containing all + * the modules currently loaded. + */ +struct elf_module { + char name[MODULE_NAME_SIZE]; // The module name + + int shallow; // Whether the module contains any code + + 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_t *init_func; // The initialization entry point + module_exit_t *exit_func; // The module finalization code + + + 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 + + Elf32_Word *hash_table; // The symbol hash table + Elf32_Word *ghash_table; // The GNU style hash table + char *str_table; // The string table + void *sym_table; // The symbol table + void *got; // The Global Offset Table + Elf32_Dyn *dyn_table; // Dynamic loading information table + + Elf32_Word strtable_size; // The size of the string table + Elf32_Word syment_size; // The size of a symbol entry + Elf32_Word symtable_size; // The size of the symbol table + + + // Transient - Data available while the module is loading + FILE *_file; // The file object of the open file + Elf32_Off _cr_offset; // The current offset in the open file +}; + +/** + * struct module_dep - structure encapsulating a module dependency need + * + * This structure represents an item in a double linked list of predecessors or + * successors. The item contents is a pointer to the corresponding module descriptor. + */ +struct module_dep { + struct list_head list; // The list entry in the dependency list + + struct elf_module *module; // The target module descriptor +}; + + + +#ifdef DYNAMIC_MODULE + +/* + * This portion is included by dynamic (ELF) module source files. + */ + + + +#define MODULE_INIT(fn) static module_init_t __module_init \ + __used __attribute__((section(".ctors_module"))) = fn + +#define MODULE_EXIT(fn) static module_exit_t __module_exit \ + __used __attribute__((section(".dtors_module"))) = fn + +#else + +/* + * This portion is included by the core COM32 module. + */ + +/* + * Accepted values for various ELF header parameters found in an ELF dynamic + * object. + */ +#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules +#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value +#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess +#define MODULE_ELF_VERSION EV_CURRENT // Object version +#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so) +#define MODULE_ELF_MACHINE EM_386 // Target architecture + +/** + * Names of symbols with special meaning (treated as special cases at linking) + */ +#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name +#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name + +/** + * modules_init - initialize the module subsystem. + * + * This function must be called before any module operation is to be performed. + */ +extern int modules_init(void); + + +/** + * modules_term - releases all resources pertaining to the module subsystem. + * + * This function should be called after all module operations. + */ +extern void modules_term(void); + + +/** + * module_alloc - reserves space for a new module descriptor. + * @name: the file name of the module to be loaded. + * + * The function simply allocates a new module descriptor and initializes its fields + * in order to be used by subsequent loading operations. + */ +extern struct elf_module *module_alloc(const char *name); + + +/** + * module_load - loads a regular ELF module into memory. + * @module: the module descriptor returned by module_alloc. + * + * The function reads the module file, checks whether the file has a + * valid structure, then loads into memory the code and the data and performs + * any symbol relocations. A module dependency is created automatically when the + * relocated symbol is defined in a different module. + * + * The function returns 0 if the operation is completed successfully, and + * a non-zero value if an error occurs. Possible errors include invalid module + * structure, missing symbol definitions (unsatisfied dependencies) and memory + * allocation issues. + */ +extern int module_load(struct elf_module *module); + + +/** + * module_load_shallow - loads a shallow ELF module into memory. + * @module: the module descriptor returned by module_alloc. + * + * The function reads the module file, checks whether the file has a valid + * structure, then loads into memory the module metadata. The metadata currently + * contains a symbol table that describes code & data allocated by other means. + * Its current use is to describe the root COM32 module to the rest of the + * module subsystem. + */ +extern int module_load_shallow(struct elf_module *module); + +/** + * module_unload - unloads the module from the system. + * @module: the module descriptor structure. + * + * The function checks to see whether the module can be safely removed, then + * it releases all the associated memory. This function can be applied both + * for standard modules and for shallow modules. + * + * A module can be safely removed from the system when no other modules reference + * symbols from it. + */ +extern int module_unload(struct elf_module *module); + +/** + * module_find - searches for a module by its name. + * @name: the name of the module, as it was specified in module_alloc. + * + * The function returns a pointer to the module descriptor, if found, or + * NULL otherwise. + */ +extern struct elf_module *module_find(const char *name); + +/** + * module_find_symbol - searches for a symbol definition in a given module. + * @name: the name of the symbol to be found. + * @module: the module descriptor structure. + * + * The function searches the module symbol table for a symbol matching exactly + * the name provided. The operation uses the following search algorithms, in this + * order: + * - If a GNU hash table is present in the module, it is used to find the symbol. + * - If the symbol cannot be found with the first method (either the hash table + * is not present or the symbol is not found) and if a regular (SysV) hash table + * is present, a search is performed on the SysV hash table. If the symbol is not + * found, NULL is returned. + * - If the second method cannot be applied, a linear search is performed by + * inspecting every symbol in the symbol table. + * + * If the symbol is found, a pointer to its descriptor structure is returned, and + * NULL otherwise. + */ +extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module); + +/** + * global_find_symbol - searches for a symbol definition in the entire module namespace. + * @name: the name of the symbol to be found. + * @module: an optional (may be NULL) pointer to a module descriptor variable that + * will hold the module where the symbol was found. + * + * The function search for the given symbol name in all the modules currently + * loaded in the system, in the reverse module loading order. That is, the most + * recently loaded module is searched first, followed by the previous one, until + * the first loaded module is reached. + * + * If no module contains the symbol, NULL is returned, otherwise the return value is + * a pointer to the symbol descriptor structure. If the module parameter is not NULL, + * it is filled with the address of the module descriptor where the symbol is defined. + */ +extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module); + +/** + * module_get_absolute - converts an memory address relative to a module base address + * to its absolute value in RAM. + * @addr: the relative address to convert. + * @module: the module whose base address is used for the conversion. + * + * The function returns a pointer to the absolute memory address. + */ +static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) { + return (void*)(module->base_addr + addr); +} + +#endif // DYNAMIC_MODULE + +#endif // MODULE_H_ diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 9c3084e9..44064faa 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -49,6 +49,10 @@ LIBENTRY_OBJS = \ sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \ sys/isatty.o sys/fstat.o +LIBMODULE_OBJS = \ + sys/module/common.o sys/module/elf_module.o \ + sys/module/shallow_module.o sys/module/elfutils.o + LIBSYSLINUX_OBJS = \ syslinux/idle.o syslinux/reboot.o \ syslinux/features.o syslinux/config.o syslinux/serial.o \ @@ -147,7 +151,8 @@ MINLIBOBJS = \ $(LIBENTRY_OBJS) \ $(LIBSYSLINUX_OBJS) \ $(LIBGCC_OBJS) \ - $(LIBCONSOLE_OBJS) + $(LIBCONSOLE_OBJS) \ + $(LIBMODULE_OBJS) DYNLIBOBJS = \ $(LIBZLIB_OBJS) \ diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c new file mode 100644 index 00000000..88fa4595 --- /dev/null +++ b/com32/lib/sys/module/common.c @@ -0,0 +1,497 @@ +/* + * common.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur + */ + +#include +#include +#include + +#include + +#include +#include + +#include "common.h" + +/** + * The one and only list of loaded modules + */ +LIST_HEAD(modules); + +// User-space debugging routines +#ifdef ELF_DEBUG +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)); +} + +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 + + +/* + * Image files manipulation routines + */ + +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; +} + + +int image_unload(struct elf_module *module) { + if (module->_file != NULL) { + fclose(module->_file); + module->_file = NULL; + } + module->_cr_offset = 0; + + return 0; +} + +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; +} + +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; +} + +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; +} + +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. +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; +} + + +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; +} + +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; +} + +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; +} + + +// 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; +} diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h new file mode 100644 index 00000000..a13027a6 --- /dev/null +++ b/com32/lib/sys/module/common.h @@ -0,0 +1,70 @@ +/* + * common.h - Common internal operations performed by the module subsystem + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur + */ + +#ifndef COMMON_H_ +#define COMMON_H_ + +#include + +#include +#include + +#include + + +// 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)) + + +#ifdef ELF_DEBUG +#define DBG_PRINT(fmt, args...) fprintf(stderr, "[DBG] " fmt, ##args) +#else +#define DBG_PRINT(fmt, args...) // Expand to nothing +#endif + +/** + * modules - A global linked list containing all the loaded modules. + */ +extern struct list_head modules; + +// User-space debugging routines +#ifdef ELF_DEBUG + +extern void print_elf_ehdr(Elf32_Ehdr *ehdr); +extern void print_elf_symbols(struct elf_module *module); + +#endif //ELF_DEBUG + +/* + * Image files manipulation routines + */ + +extern int image_load(struct elf_module *module); +extern int image_unload(struct elf_module *module); +extern int image_read(void *buff, size_t size, struct elf_module *module); +extern int image_skip(size_t size, struct elf_module *module); +extern int image_seek(Elf32_Off offset, struct elf_module *module); + +extern struct module_dep *module_dep_alloc(struct elf_module *module); + +extern int check_header_common(Elf32_Ehdr *elf_hdr); + +extern int enforce_dependency(struct elf_module *req, struct elf_module *dep); +extern int clear_dependency(struct elf_module *req, struct elf_module *dep); + +extern int check_symbols(struct elf_module *module); + + +#endif /* COMMON_H_ */ diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c new file mode 100644 index 00000000..82f1be89 --- /dev/null +++ b/com32/lib/sys/module/elf_module.c @@ -0,0 +1,465 @@ +/* + * elf_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur + */ + + +#include +#include +#include +#include + +#include +#include +#include + +#include "common.h" + + +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; +} + +/* + * + * 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 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 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 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_t*)module_get_absolute( + init_sym->st_value, module); + + module->exit_func = (module_exit_t*)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; +} diff --git a/com32/lib/sys/module/elfutils.c b/com32/lib/sys/module/elfutils.c new file mode 100644 index 00000000..ce781a08 --- /dev/null +++ b/com32/lib/sys/module/elfutils.c @@ -0,0 +1,89 @@ +#include +#include + +#include + +unsigned long elf_hash(const unsigned char *name) { + unsigned long h = 0; + unsigned long g; + + while (*name) { + h = (h << 4) + *name++; + if ((g = h & 0xF0000000)) + h ^= g >> 24; + + h &= ~g; + } + + return h; +} + +unsigned long elf_gnu_hash(const unsigned char *name) { + unsigned long h = 5381; + unsigned char c; + + for (c = *name; c != '\0'; c = *++name) { + h = h * 33 + c; + } + + return h & 0xFFFFFFFF; +} + +#ifdef ELF_NO_POSIX_MEMALIGN + +struct memalign_info { + void *start_addr; + char data[0]; +}; + +int elf_malloc(void **memptr, size_t alignment, size_t size) { + void *start_addr = NULL; + struct memalign_info *info; + + if ((alignment & (alignment - 1)) != 0) + return EINVAL; + if (alignment % sizeof(void*) != 0) + alignment = sizeof(void*); + + start_addr = malloc(size + (alignment > sizeof(struct memalign_info) ? + alignment : sizeof(struct memalign_info))); + + if (start_addr == NULL) + return ENOMEM; + + + info = (struct memalign_info*)(start_addr - + ((unsigned long)start_addr % alignment) + + alignment - sizeof(struct memalign_info)); + + info->start_addr = start_addr; + + *memptr = info->data; + + return 0; +} + +void elf_free(void *memptr) { + struct memalign_info *info = (struct memalign_info*)(memptr - + sizeof(struct memalign_info)); + + free(info->start_addr); +} + +#else + +int elf_malloc(void **memptr, size_t alignment, size_t size) { + if ((alignment & (alignment - 1)) != 0) + return EINVAL; + + if (alignment % sizeof(void*) != 0) + alignment = sizeof(void*); + + return posix_memalign(memptr, alignment, size); +} + +void elf_free(void *memptr) { + free(memptr); +} + +#endif //ELF_NO_POSIX_MEMALIGN diff --git a/com32/lib/sys/module/shallow_module.c b/com32/lib/sys/module/shallow_module.c new file mode 100644 index 00000000..c4a9ff15 --- /dev/null +++ b/com32/lib/sys/module/shallow_module.c @@ -0,0 +1,152 @@ +/* + * shallow_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur + */ + +#include "common.h" + +#include +#include + + +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; +} + +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; +} + + +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; +} -- cgit v1.2.3