diff options
-rw-r--r-- | com32/Makefile | 3 | ||||
-rw-r--r-- | com32/elflink/Makefile | 104 | ||||
-rw-r--r-- | com32/elflink/Makefile.user (renamed from elf/Makefile) | 3 | ||||
-rw-r--r-- | com32/elflink/README (renamed from elf/README) | 0 | ||||
-rw-r--r-- | com32/elflink/TODO | 1 | ||||
-rw-r--r-- | com32/elflink/elf_module.c (renamed from elf/elf_module.c) | 359 | ||||
-rw-r--r-- | com32/elflink/elf_module.h (renamed from elf/elf_module.h) | 0 | ||||
-rw-r--r-- | com32/elflink/elf_utils.c | 70 | ||||
-rw-r--r-- | com32/elflink/elf_utils.h (renamed from elf/elf_utils.h) | 8 | ||||
-rw-r--r-- | com32/elflink/elflink.c | 6 | ||||
-rw-r--r-- | com32/elflink/elftest.c (renamed from elf/elftest.c) | 0 | ||||
-rw-r--r-- | com32/elflink/hello_def.c (renamed from elf/hello_def.c) | 0 | ||||
-rw-r--r-- | com32/elflink/hello_ref.c (renamed from elf/hello_ref.c) | 0 | ||||
-rw-r--r-- | com32/elflink/linux_list.h (renamed from elf/linux_list.h) | 0 | ||||
-rw-r--r-- | com32/include/sys/elfcommon.h | 229 | ||||
-rw-r--r-- | elf/TODO | 3 | ||||
-rw-r--r-- | elf/elf_utils.c | 27 |
17 files changed, 577 insertions, 236 deletions
diff --git a/com32/Makefile b/com32/Makefile index 64049d07..22bbbc16 100644 --- a/com32/Makefile +++ b/com32/Makefile @@ -1,3 +1,4 @@ -SUBDIRS = lib gpllib libutil modules menu samples rosh cmenu hdt +SUBDIRS = lib gpllib libutil modules menu samples elflink rosh cmenu hdt + all tidy dist clean spotless install: set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile new file mode 100644 index 00000000..1151c677 --- /dev/null +++ b/com32/elflink/Makefile @@ -0,0 +1,104 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## COM32 standard modules +## + +TMPFILE = $(shell mktemp /tmp/gcc_ok.XXXXXX) +CC = gcc + +gcc_ok = $(shell tmpf=$(TMPFILE); if $(CC) $(1) -c -x c /dev/null -o $$tmpf 2>/dev/null; \ + then echo $(1); else echo $(2); fi; rm -f $$tmpf) + +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-fno-stack-protector,) + +LD = ld -m elf_i386 +AR = ar +NASM = nasm +NASMOPT = -O9999 +RANLIB = ranlib +CFLAGS = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -march=i386 -Os \ + -fomit-frame-pointer -D__COM32__ \ + -nostdinc -iwithprefix include \ + -I../libutil/include -I../include \ + -Wp,-MT,$@,-MD,$(dir $@).$(notdir $@).d +LNXCFLAGS = -W -Wall -O -g -I../libutil/include +LNXSFLAGS = -g +LNXLDFLAGS = -g +SFLAGS = -D__COM32__ -march=i386 +LDFLAGS = -T ../lib/com32.ld +OBJCOPY = objcopy +PPMTOLSS16 = ../ppmtolss16 +LIBGCC := $(shell $(CC) --print-libgcc) +LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC) +LNXLIBS = ../libutil/libutil_lnx.a + +.SUFFIXES: .lss .c .o .elf .c32 .lnx + +BINDIR = /usr/bin +LIBDIR = /usr/lib +DATADIR = /usr/share +AUXDIR = $(DATADIR)/syslinux +INCDIR = /usr/include +COM32DIR = $(AUXDIR)/com32 + +MODULES = elflink.c32 + +TESTFILES = + +all: $(MODULES) $(TESTFILES) + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -c -o $@ $< + +.PRECIOUS: %.o +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +.PRECIOUS: %.elf +%.elf: %.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +.PRECIOUS: %.lo +%.lo: %.S + $(CC) $(LNXSFLAGS) -c -o $@ $< + +.PRECIOUS: %.lo +%.lo: %.c + $(CC) $(LNXCFLAGS) -c -o $@ $< + +.PRECIOUS: %.lnx +%.lnx: %.lo $(LNXLIBS) + $(CC) $(LNXLDFLAGS) -o $@ $^ + +%.c32: %.elf + $(OBJCOPY) -O binary $< $@ + +elflink.elf : elflink.o elf_module.o elf_utils.o $(LIBS) + $(LD) $(LDFLAGS) -o $@ $^ + +tidy dist: + rm -f *.o *.lo *.a *.lst *.elf .*.d + +clean: tidy + rm -f *.lss *.c32 *.lnx *.com + +spotless: clean + rm -f *~ \#* + +install: all + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) + install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR) + +-include .*.d diff --git a/elf/Makefile b/com32/elflink/Makefile.user index e7d0ba64..e800d6c6 100644 --- a/elf/Makefile +++ b/com32/elflink/Makefile.user @@ -1,3 +1,6 @@ +## Builds a simple user-space application that tests the basic functionality +## of the ELF linking routines. + ## License would go here ######## diff --git a/elf/README b/com32/elflink/README index 324a8c25..324a8c25 100644 --- a/elf/README +++ b/com32/elflink/README diff --git a/com32/elflink/TODO b/com32/elflink/TODO new file mode 100644 index 00000000..19cc04ac --- /dev/null +++ b/com32/elflink/TODO @@ -0,0 +1 @@ +* Create a macro for reporting debugging information. diff --git a/elf/elf_module.c b/com32/elflink/elf_module.c index 24137402..000ec0b1 100644 --- a/elf/elf_module.c +++ b/com32/elflink/elf_module.c @@ -19,14 +19,14 @@ #define MAX(x,y) (((x) > (y)) ? (x) : (y)) // The list of loaded modules -static LIST_HEAD(modules); +static LIST_HEAD(modules); // User-space debugging routines #ifdef ELF_USERSPACE_TEST static void print_elf_ehdr(Elf32_Ehdr *ehdr) { int i; - + printf("Identification:\t"); for (i=0; i < EI_NIDENT; i++) { printf("%d ", ehdr->e_ident[i]); @@ -48,18 +48,18 @@ static void print_elf_symbols(struct elf_module *module) { Elf32_Word *chn = module->hash_table + 2 + module->hash_table[0]; Elf32_Word i, crt_index; Elf32_Sym *crt_sym; - + printf("Bucket count: %d \n", module->hash_table[0]); printf("Chain count: %d (Non GNU-Hash: %d)\n", module->hash_table[1], module->ghash_table[1]); - + for (i = 0; i < module->hash_table[0]; i++) { printf("Bucket %d:\n", i); crt_index = bkt[i]; - + while (crt_index != STN_UNDEF) { crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size); - + printf("%s\n", module->str_table + crt_sym->st_name); crt_index = chn[crt_index]; } @@ -69,27 +69,27 @@ static void print_elf_symbols(struct elf_module *module) { static int image_load(struct elf_module *module) { char file_name[MODULE_NAME_SIZE+3]; // Include the extension - + strcpy(file_name, module->name); strcat(file_name, ".so"); - + module->_file = fopen(file_name, "rb"); - + if (module->_file == NULL) { perror("Could not open object file"); goto error; } module->_cr_offset = 0; - + return 0; - + error: if (module->_file != NULL) { fclose(module->_file); module->_file = NULL; } - + return -1; } @@ -100,16 +100,16 @@ static int image_unload(struct elf_module *module) { 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; - + printf("[DBG] Read %u\n", size); module->_cr_offset += size; return 0; @@ -118,17 +118,17 @@ static int image_read(void *buff, size_t size, struct elf_module *module) { 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; - + printf("[DBG] Skipped %u\n", size); module->_cr_offset += size; return 0; @@ -137,7 +137,7 @@ static int image_skip(size_t size, struct elf_module *module) { 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); } @@ -149,42 +149,42 @@ int modules_init() { // Termination of the module subsystem void modules_term() { - + } // 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; } @@ -196,48 +196,48 @@ static int check_header(Elf32_Ehdr *elf_hdr) { elf_hdr->e_ident[EI_MAG1] != ELFMAG1 || elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { - + fprintf(stderr, "The file is not an ELF object\n"); return -1; } - + if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) { fprintf(stderr, "Invalid ELF class code\n"); return -1; } - + if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) { fprintf(stderr, "Invalid ELF data encoding\n"); return -1; } - + if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION || elf_hdr->e_version != MODULE_ELF_VERSION) { fprintf(stderr, "Invalid ELF file version\n"); return -1; } - + if (elf_hdr->e_type != MODULE_ELF_TYPE) { fprintf(stderr, "The ELF file must be a shared object\n"); return -1; } - - + + if (elf_hdr->e_machine != MODULE_ELF_MACHINE) { fprintf(stderr, "Invalid ELF architecture\n"); return -1; } - + if (elf_hdr->e_phoff == 0x00000000) { fprintf(stderr, "PHT missing\n"); return -1; } - + return 0; } /* - * + * * The implementation assumes that the loadable segments are present * in the PHT sorted by their offsets, so that only forward seeks would * be necessary. @@ -247,33 +247,33 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { 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: + 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; @@ -285,44 +285,44 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { break; } } - + if (max_addr - min_addr == 0) { // No loadable segments fprintf(stderr, "No loadable segments found\n"); goto out; } - + if (dyn_addr == 0) { fprintf(stderr, "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 (posix_memalign(&module->module_addr, - max_align, + + + if (elf_malloc(&module->module_addr, + max_align, max_alloc-min_alloc) != 0) { - + fprintf(stderr, "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) { @@ -330,7 +330,7 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { // 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; @@ -341,58 +341,58 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) { res = -1; goto out; } - - if (image_read(module_get_absolute(cr_pht->p_vaddr, module), + + if (image_read(module_get_absolute(cr_pht->p_vaddr, module), cr_pht->p_filesz, module) < 0) { res = -1; goto out; } } - + printf("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); - + printf("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, max_align); printf("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) { +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 = + module->hash_table = (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module); break; case DT_GNU_HASH: // TODO: Add support for this one, too (50% faster) - module->ghash_table = + module->ghash_table = (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module); break; case DT_STRTAB: - module->str_table = + module->str_table = (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module); break; case DT_SYMTAB: - module->sym_table = + module->sym_table = module_get_absolute(dyn_entry->d_un.d_ptr, module); break; case DT_STRSZ: @@ -405,91 +405,91 @@ static int prepare_dynlinking(struct elf_module *module) { module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module); break; } - + dyn_entry++; } - - + + 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 *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 fprintf(stderr, "Warning: Cannot perform relocation for symbol %s\n", @@ -497,16 +497,16 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { // TODO: Return an error return 0; } - + // Compute the absolute symbol virtual address sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module); - + if (sym_module != module) { // Create a dependency enforce_dependency(sym_module, module); } } - + switch (type) { case R_386_NONE: // Do nothing @@ -534,27 +534,28 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { fprintf(stderr, "Warning: Relocation type %d not supported\n", type); break; } - + return 0; } static int resolve_symbols(struct elf_module *module) { Elf32_Dyn *dyn_entry = module->dyn_table; - int i, res; - + 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; @@ -567,7 +568,7 @@ static int resolve_symbols(struct elf_module *module) { 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); @@ -578,7 +579,7 @@ static int resolve_symbols(struct elf_module *module) { case DT_RELENT: rel_entry = dyn_entry->d_un.d_val; break; - + // Module initialization and termination case DT_INIT: // TODO Implement initialization functions @@ -587,59 +588,59 @@ static int resolve_symbols(struct elf_module *module) { // 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) { - int i; + unsigned int i; Elf32_Sym *crt_sym, *ref_sym; char *crt_name; struct elf_module *crt_module; - + int strong_count; int weak_count; - + // The chain count gives the number of symbols for (i = 1; i < module->hash_table[1]; 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)) { @@ -652,7 +653,7 @@ static int check_symbols(struct elf_module *module) { } } } - + if (crt_sym->st_shndx == SHN_UNDEF) { // We have an undefined symbol if (strong_count == 0 && weak_count == 0) { @@ -667,7 +668,7 @@ static int check_symbols(struct elf_module *module) { } } } - + return 0; } @@ -675,56 +676,60 @@ static int check_symbols(struct elf_module *module) { 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; } - + CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error); - + // Checking the header signature and members CHECKED(res, check_header(&elf_hdr), error); // DEBUG +#ifdef ELF_USERSPACE_TEST print_elf_ehdr(&elf_hdr); - +#endif // ELF_USERSPACE_TEST + // Load the segments in the memory CHECKED(res, load_segments(module, &elf_hdr), error); // Obtain dynamic linking information CHECKED(res, prepare_dynlinking(module), error); - + // DEBUG +#ifdef ELF_USERSPACE_TEST print_elf_symbols(module); - +#endif // ELF_USERSPACE_TEST + // 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); - + // Perform the relocations resolve_symbols(module); - + // The file image is no longer needed image_unload(module); - - + + return 0; - + error: // Remove the module from the module list (if applicable) list_del_init(&module->list); - + if (module->module_addr != NULL) { - free(module->module_addr); + elf_free(module->module_addr); module->module_addr = NULL; } - + image_unload(module); - + return res; } @@ -736,20 +741,20 @@ int module_unload(struct elf_module *module) { fprintf(stderr, "Module is required by other modules.\n"); return -1; } - + // Remove any dependency information list_for_each_entry_safe(crt_dep, tmp, &module->required, list) { clear_dependency(crt_dep->module, module); } - + // Remove the module from the module list list_del_init(&module->list); - + // Release the loaded segments - free(module->module_addr); + elf_free(module->module_addr); // Release the module structure free(module); - + return 0; } @@ -757,76 +762,76 @@ int module_unload(struct elf_module *module) { 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) { fprintf(stderr, "Warning: 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) & + 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 + + 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; } @@ -834,19 +839,19 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo } while ((*hasharr++ & 1u) == 0); } } - + 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) result = module_find_symbol_sysv(name, module); - + return result; } @@ -854,10 +859,10 @@ 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: @@ -877,6 +882,6 @@ Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) { } } } - + return result; } diff --git a/elf/elf_module.h b/com32/elflink/elf_module.h index 1454ee71..1454ee71 100644 --- a/elf/elf_module.h +++ b/com32/elflink/elf_module.h diff --git a/com32/elflink/elf_utils.c b/com32/elflink/elf_utils.c new file mode 100644 index 00000000..be320772 --- /dev/null +++ b/com32/elflink/elf_utils.c @@ -0,0 +1,70 @@ +#include <stdlib.h> +#include <errno.h> + +#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; +} + + +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) + return EINVAL; + + 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); +} diff --git a/elf/elf_utils.h b/com32/elflink/elf_utils.h index 888d912a..b8df660e 100644 --- a/elf/elf_utils.h +++ b/com32/elflink/elf_utils.h @@ -2,6 +2,7 @@ #define ELF_UTILS_H_ #include <elf.h> +#include <stdlib.h> // Returns a pointer to the ELF header structure static inline Elf32_Ehdr *elf_get_header(void *elf_image) { @@ -11,7 +12,7 @@ static inline Elf32_Ehdr *elf_get_header(void *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); } @@ -19,11 +20,14 @@ static inline Elf32_Phdr *elf_get_pht(void *elf_image) { 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/elflink.c b/com32/elflink/elflink.c new file mode 100644 index 00000000..22b0db5d --- /dev/null +++ b/com32/elflink/elflink.c @@ -0,0 +1,6 @@ +#include "elf_module.h" + +int main(int argc, char **argv) { + return 0; +} + diff --git a/elf/elftest.c b/com32/elflink/elftest.c index 0a38bbe6..0a38bbe6 100644 --- a/elf/elftest.c +++ b/com32/elflink/elftest.c diff --git a/elf/hello_def.c b/com32/elflink/hello_def.c index 2ad60233..2ad60233 100644 --- a/elf/hello_def.c +++ b/com32/elflink/hello_def.c diff --git a/elf/hello_ref.c b/com32/elflink/hello_ref.c index f7b798b4..f7b798b4 100644 --- a/elf/hello_ref.c +++ b/com32/elflink/hello_ref.c diff --git a/elf/linux_list.h b/com32/elflink/linux_list.h index 3b92e254..3b92e254 100644 --- a/elf/linux_list.h +++ b/com32/elflink/linux_list.h diff --git a/com32/include/sys/elfcommon.h b/com32/include/sys/elfcommon.h index cc8f9235..8d6ddb05 100644 --- a/com32/include/sys/elfcommon.h +++ b/com32/include/sys/elfcommon.h @@ -59,32 +59,108 @@ #define EM_S390_OLD 0xA390 /* Obsolete interrim value for S/390 */ /* Dynamic type values */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ + +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 /* Auxilliary table entries */ #define AT_NULL 0 /* end of vector */ @@ -147,6 +223,52 @@ #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff +/* Symbol table definitions */ + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + /* Lenght of magic at the start of a file */ #define EI_NIDENT 16 @@ -184,4 +306,59 @@ #define ELFOSABI_NONE 0 #define ELFOSABI_LINUX 3 +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + #endif /* _SYS_ELFCOMMON_H */ diff --git a/elf/TODO b/elf/TODO deleted file mode 100644 index 9dc92fe3..00000000 --- a/elf/TODO +++ /dev/null @@ -1,3 +0,0 @@ -* Check to see whether the module is already inserted. -* Perform unloading cleanup properly. -* Create a macro for reporting debugging information. diff --git a/elf/elf_utils.c b/elf/elf_utils.c deleted file mode 100644 index 157dc2a8..00000000 --- a/elf/elf_utils.c +++ /dev/null @@ -1,27 +0,0 @@ -#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; -} |