From 9a243b9ccd6f48dda83e40ebfe1988b75691f667 Mon Sep 17 00:00:00 2001 From: Armin Luntzer <armin.luntzer@univie.ac.at> Date: Wed, 10 Oct 2018 11:48:20 +0200 Subject: [PATCH] * change API of apply_relocate_add() to accept ELF section name * add ELF utility functions: - elf_get_symbol_shndx() - elf_get_common_size() - elf_get_common_objects() - elf_get_symbol_size() * adapt module so that more complex executables may be loaded, i.e. - allocate "common" objects in relocatable executables - relocate ".data" sections - add elf utility fuctions NOTE: these changes are an experimental mess at this time and must not be merged to master until properly tidied up --- arch/sparc/kernel/module.c | 9 +- include/kernel/elf.h | 6 ++ include/kernel/module.h | 3 +- kernel/module.c | 202 +++++++++++++++++++++++++++++++----- lib/elf.c | 207 ++++++++++++++++++++++++++++++++++++- 5 files changed, 396 insertions(+), 31 deletions(-) diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 1736686..2383114 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -16,11 +16,12 @@ * @param m an ELF module * @param rel an ELF relocation entry * @param sym the address of the target symbol + * @param sec_name the name of the section to apply the relocation in * * return 0 on success */ -int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym) +int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym, const char *sec_name) { Elf_Addr rsym; @@ -40,9 +41,13 @@ int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym) if (!sym) return -EINVAL; + if (!sec_name) { + pr_err("\tsec_name empty!\n"); + return -EINVAL; + } - text = find_mod_sec(m, ".text"); + text = find_mod_sec(m, sec_name); loc8 = (uint8_t *) (text->addr + rel->r_offset); loc32 = (uint32_t *) loc8; diff --git a/include/kernel/elf.h b/include/kernel/elf.h index 4797c13..79739dc 100644 --- a/include/kernel/elf.h +++ b/include/kernel/elf.h @@ -568,6 +568,9 @@ int elf_header_check(Elf_Ehdr *ehdr); Elf_Shdr *elf_get_shdr(const Elf_Ehdr *ehdr); size_t elf_find_shdr_alloc_idx(const Elf_Ehdr *ehdr, const size_t offset); +size_t elf_get_common_size(const Elf_Ehdr *ehdr); +size_t elf_get_common_objects(const Elf_Ehdr *ehdr, char **objname); + Elf_Shdr *elf_get_sec_by_idx(const Elf_Ehdr *ehdr, const size_t idx); Elf_Shdr *elf_get_sec_shstrtab(const Elf_Ehdr *ehdr); char *elf_get_shstrtab_str(const Elf_Ehdr *ehdr, size_t idx); @@ -586,6 +589,7 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr, const char *name, unsigned long *value); unsigned long elf_get_symbol_type(const Elf_Ehdr *ehdr, const char *name); +size_t elf_get_symbol_size(const Elf_Ehdr *ehdr, const char *name); size_t elf_find_sec_idx_by_type(const Elf_Ehdr *ehdr, const uint32_t sh_type, @@ -606,4 +610,6 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr); void elf_dump_sections(const Elf_Ehdr *ehdr); +unsigned short elf_get_symbol_shndx(const Elf_Ehdr *ehdr, + const char *name); #endif /* _KERNEL_ELF_H_ */ diff --git a/include/kernel/module.h b/include/kernel/module.h index e357eaf..dc3584d 100644 --- a/include/kernel/module.h +++ b/include/kernel/module.h @@ -62,7 +62,8 @@ struct elf_module { /* implemented in architecture code */ -int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym); +int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym, + const char *sec_name); struct module_section *find_mod_sec(const struct elf_module *m, diff --git a/kernel/module.c b/kernel/module.c index b15a5d7..aab0150 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -69,6 +69,28 @@ struct module_section *find_mod_sec(const struct elf_module *m, } +/** + * @brief find module section by index + * + * @param m a struct elf_module + * + * @param idx the index of the module section + * + * @return module section structure pointer or NULL if not found + */ + +struct module_section *find_mod_idx(const struct elf_module *m, + size_t idx) + +{ + if (idx >= m->num_sec) + return NULL; + + return &m->sec[idx]; +} + + + /** * @brief setup the module structure * @@ -178,8 +200,13 @@ static int module_load_mem(struct elf_module *m) sec = elf_get_sec_by_idx(m->ehdr, idx); +#if 0 if (!sec->sh_size) /* don't need those */ continue; +#else + if (!(sec->sh_flags & SHF_ALLOC)) + continue; +#endif s->size = sec->sh_size; @@ -193,24 +220,27 @@ static int module_load_mem(struct elf_module *m) goto error; strcpy(s->name, src); + + pr_err(MOD "section %s index %d max %d\n", s->name, s, m->num_sec); if (sec->sh_type & SHT_NOBITS) { - pr_debug(MOD "\tZero segment %10s at %p size %ld\n", + pr_info(MOD "\tZero segment %10s at %p size %ld\n", s->name, (char *) va_load, sec->sh_size); bzero((void *) va_load, s->size); } else { - pr_debug(MOD "\tCopy segment %10s from %p to %p size %ld\n", + pr_info(MOD "\tCopy segment %10s from %p to %p size %ld\n", s->name, (char *) m->ehdr + sec->sh_offset, (char *) va_load, sec->sh_size); - memcpy((void *) va_load, - (char *) m->ehdr + sec->sh_offset, - sec->sh_size); + if (sec->sh_size) + memcpy((void *) va_load, + (char *) m->ehdr + sec->sh_offset, + sec->sh_size); } s->addr = va_load; @@ -219,10 +249,84 @@ static int module_load_mem(struct elf_module *m) s++; if (s > &m->sec[m->num_sec]) { - pr_debug(MOD "Error out of section memory\n"); + pr_err(MOD "Error out of section memory\n"); + goto error; + } + } + +#if 0 + if (elf_get_common_size(m->ehdr)) { + + m->num_sec++; + m->sec = (struct module_section *) + krealloc(m->sec, sizeof(struct module_section) * m->num_sec); + + if (!m->sec) + goto error; + + s = &m->sec[m->num_sec - 1]; + + s->size = elf_get_common_size(m->ehdr); + s->addr = (unsigned long) kzalloc(s->size); + if (!s->addr) + goto error; + + pr_info(MOD "\tcreating .alloc section of %d bytes at %x\n", s->size, s->addr); + + s->name = kmalloc(strlen(".alloc")); + if (!s->name) + goto error; + + strcpy(s->name, ".alloc"); + + } +#else + /* yes, yes, fixup like everything else here */ + if (elf_get_common_objects(m->ehdr, NULL)) { + size_t cnt = elf_get_common_objects(m->ehdr, NULL); + char **obj; + + m->sec = (struct module_section *) + krealloc(m->sec, sizeof(struct module_section) * (m->num_sec + cnt)); + + if (!m->sec) goto error; + + + /* point to last */ + s = &m->sec[m->num_sec]; + /* and update */ + m->num_sec += cnt; + + obj = kmalloc(cnt * sizeof(char **)); + if (!obj) + goto error; + /* load names */ + elf_get_common_objects(m->ehdr, obj); + + + /* Allocate one section entry for each object, this is not + * that efficient, but what the heck. Better not to have + * uninitialised non-static globals at all! + */ + for (idx = 0; idx < cnt; idx++) { + s->size = elf_get_symbol_size(m->ehdr, obj[idx]); + s->addr = (unsigned long) kzalloc(s->size); + if (!s->addr) + goto error; + pr_debug(MOD "\tcreating \"%s\" section of %d bytes at %x\n", obj[idx], s->size, s->addr); + s->name = kmalloc(strlen(obj[idx])); + if (!s->name) + goto error; + strcpy(s->name, obj[idx]); + s++; } + + kfree(obj); } +#endif + + return 0; @@ -264,11 +368,12 @@ static int module_relocate(struct elf_module *m) if (m->ehdr->e_type != ET_DYN) return 0; - /* we only need RELA type relocations */ while (1) { + char *rel_sec; + idx = elf_find_sec_idx_by_type(m->ehdr, SHT_RELA, idx + 1); if (!idx) @@ -276,8 +381,16 @@ static int module_relocate(struct elf_module *m) sec = elf_get_sec_by_idx(m->ehdr, idx); - pr_debug(MOD "\n" - MOD "Section Header info: %ld\n", sec->sh_info); + pr_info(MOD "\n" + MOD "Section Header info: %ld %s\n", sec->sh_info, elf_get_shstrtab_str(m->ehdr, idx)); + + if (!strcmp(elf_get_shstrtab_str(m->ehdr, idx), ".rela.text")) + rel_sec = ".text"; + else if (!strcmp(elf_get_shstrtab_str(m->ehdr, idx), ".rela.data")) + rel_sec = ".data"; + else + BUG(); + if (sec) { @@ -295,8 +408,8 @@ static int module_relocate(struct elf_module *m) unsigned int symsec = ELF_R_SYM(relatab[i].r_info); char *symstr = elf_get_symbol_str(m->ehdr, symsec); struct module_section *s; - struct module_section *text = find_mod_sec(m, ".text"); - + struct module_section *text = find_mod_sec(m, ".text"); /* ?? rel_sec ?? */ + pr_debug(MOD "OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n", relatab[i].r_offset, relatab[i].r_info, @@ -308,23 +421,63 @@ static int module_relocate(struct elf_module *m) if (strlen(symstr)) { - Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr); + unsigned long symval; + Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr); - if (!sym) { + if (!sym) { + pr_debug(MOD "\tSymbol %s not found in library, trying to resolving in module\n", + symstr); - unsigned long symval; - pr_info(MOD "\tSymbol %s not found in library, trying to resolving in module\n", - symstr); + if ((elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) { + char *secstr; - if (!(elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) { - pr_debug(MOD "\tERROR, object data resolution not yet implemented, symbol %s may not function as intended. If it is a variable, declare it static as a workaround\n", symstr); - } + s = find_mod_sec(m, elf_get_shstrtab_str(m->ehdr, elf_get_symbol_shndx(m->ehdr, symstr))); + + switch (elf_get_symbol_shndx(m->ehdr, symstr)) { + case SHN_UNDEF: + pr_debug(MOD "\tundefined section index\n"); + break; + case SHN_ABS: + pr_debug(MOD "\tabsolute value section index\n"); + case SHN_COMMON: + pr_debug(MOD "\t %s common symbol index (must allocate) add: %d\n", symstr, + relatab[i].r_addend); + s = find_mod_sec(m, symstr); + if (!s) { + pr_err("no suitable section found"); + return -1; + } + break; + default: + break; + + } + + + if (!s) { + pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr); + continue; + } + secstr = s->name; + /* target address to insert at location */ + reladdr = (long) s->addr; + pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx, section %s\n", reladdr, s->addr, secstr); + + /* needed ?? */ + //elf_get_symbol_value(m->ehdr, symstr, (unsigned long *) &relatab[i].r_addend); + apply_relocate_add(m, &relatab[i], reladdr, rel_sec); + continue; + + } + +#if 0 if (!(elf_get_symbol_type(m->ehdr, symstr) & (STT_FUNC | STT_OBJECT))) { pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); return -1; } +#endif if (!elf_get_symbol_value(m->ehdr, symstr, &symval)) { pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); return -1; @@ -334,25 +487,26 @@ static int module_relocate(struct elf_module *m) } - pr_debug(MOD "\tSymbol %s at %lx\n", symstr, sym); + pr_debug(MOD "\tSymbol %s at %lx val %lx sec %d\n", symstr, sym, symval, symsec); - apply_relocate_add(m, &relatab[i], sym); + apply_relocate_add(m, &relatab[i], sym, rel_sec); } else { /* no string, symtab entry is probably a section, try to identify it */ char *secstr = elf_get_shstrtab_str(m->ehdr, symsec); - s = find_mod_sec(m, secstr); + s = find_mod_idx(m, symsec-1); if (!s) { pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr); continue; } + secstr = s->name; /* target address to insert at location */ reladdr = (long) s->addr; - pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx\n", reladdr, s->addr); + pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx, section %s\n", reladdr, s->addr, secstr); - apply_relocate_add(m, &relatab[i], reladdr); + apply_relocate_add(m, &relatab[i], reladdr, rel_sec); } pr_debug(MOD "\n"); diff --git a/lib/elf.c b/lib/elf.c index 89553fd..df56bb6 100644 --- a/lib/elf.c +++ b/lib/elf.c @@ -510,6 +510,102 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr, } +/** + * @brief get the value of a symbol + * + * @param ehdr an Elf_Ehdr + * + * @param name the name of the symbol + * + * @return the size of the symbol (0 if not found or simply size 0) + * -1 on error + */ + +size_t elf_get_symbol_size(const Elf_Ehdr *ehdr, const char *name) + +{ + unsigned int i; + size_t sym_cnt; + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return -1; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug(MSG "Error %d != %ld\n", + sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if(!strcmp(elf_get_symbol_str(ehdr, i), name)) + return (size_t) symbols[i].st_size; + } + + return 0; +} + + +/** + * @brief get the section index of a symbol + * + * @param ehdr an Elf_Ehdr + * + * @param name the name of the symbol + * + * @return the section index of the symbol or -1 if not found + */ + +unsigned short elf_get_symbol_shndx(const Elf_Ehdr *ehdr, + const char *name) + +{ + unsigned int i; + size_t sym_cnt; + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return -1; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug(MSG "Error %d != %ld\n", + sizeof(Elf_Sym), symtab->sh_entsize); + return -1; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if(!strcmp(elf_get_symbol_str(ehdr, i), name)) { + return symbols[i].st_shndx; + } + } + + return -1; +} + + + /** * @brief get the ELF type of a symbol * @@ -607,14 +703,114 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr) for (i = 0; i <ehdr->e_shnum; i++) { shdr = elf_get_sec_by_idx(ehdr, i); if ((shdr->sh_flags & SHF_ALLOC)) - if (shdr->sh_size) - cnt++; + cnt++; } return cnt; } + +/* @brief get the total byte size of unallocated uninitialised common objects + * + * @param ehdr an Elf_Ehdr + * + * @return the number of bytes to be occupied by common (unallocated) objects + */ + +size_t elf_get_common_size(const Elf_Ehdr *ehdr) +{ + unsigned int i; + size_t sym_cnt; + + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + size_t bytes = 0; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return 0; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return 0; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if (symbols[i].st_shndx == SHN_COMMON) + bytes += symbols[i].st_size; + } + + return bytes; +} + + +/* @brief get the total count of unallocated uninitialised common objects + * + * @param ehdr an Elf_Ehdr + * @param[out] an index array + * + * @note set idx to NULL to determine the number of elements needed for the + * array + * + * @return the number of common objects + */ + +size_t elf_get_common_objects(const Elf_Ehdr *ehdr, char **objname) +{ + unsigned int i; + size_t sym_cnt; + + + Elf_Shdr *symtab; + Elf_Sym *symbols; + + size_t common = 0; + + + symtab = elf_find_sec(ehdr, ".symtab"); + + if (!symtab) { + pr_debug(MSG "WARN: no .symtab section found\n"); + return 0; + } + + if (symtab->sh_entsize != sizeof(Elf_Sym)) { + pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + return 0; + } + + symbols = (Elf_Sym *) (((char *) ehdr) + symtab->sh_offset); + + sym_cnt = symtab->sh_size / symtab->sh_entsize; + + for (i = 0; i < sym_cnt; i++) { + if (symbols[i].st_shndx == SHN_COMMON) { + if (objname) + objname[common] = elf_get_symbol_str(ehdr, i); + common++; + } + } + + return common; +} + + + + + + + /** * @brief get the number of entries in a dynamic section * @@ -727,7 +923,8 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr) printk(MSG "\n" MSG ".symtab contains %d entries\n" MSG "============================\n" - MSG "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\n", sym_cnt); + MSG "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\t\t[SHIDX]\n", + sym_cnt); for (i = 0; i < sym_cnt; i++) { @@ -756,7 +953,9 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr) printk("\tUNKNOWN"); break; } - printk("\t%-10s\n", elf_get_symbol_str(ehdr, i)); + printk("\t%-10s", elf_get_symbol_str(ehdr, i)); + + printk("\t%4ld\n", symbols[i].st_shndx); } } -- GitLab