Skip to content
Snippets Groups Projects
Commit 9a243b9c authored by Armin Luntzer's avatar Armin Luntzer
Browse files

* 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
parent cc24e285
No related branches found
No related tags found
No related merge requests found
...@@ -16,11 +16,12 @@ ...@@ -16,11 +16,12 @@
* @param m an ELF module * @param m an ELF module
* @param rel an ELF relocation entry * @param rel an ELF relocation entry
* @param sym the address of the target symbol * @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 * 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; Elf_Addr rsym;
...@@ -40,9 +41,13 @@ int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym) ...@@ -40,9 +41,13 @@ int apply_relocate_add(struct elf_module *m, Elf_Rela *rel, Elf_Addr sym)
if (!sym) if (!sym)
return -EINVAL; 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); loc8 = (uint8_t *) (text->addr + rel->r_offset);
loc32 = (uint32_t *) loc8; loc32 = (uint32_t *) loc8;
......
...@@ -568,6 +568,9 @@ int elf_header_check(Elf_Ehdr *ehdr); ...@@ -568,6 +568,9 @@ int elf_header_check(Elf_Ehdr *ehdr);
Elf_Shdr *elf_get_shdr(const 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_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_by_idx(const Elf_Ehdr *ehdr, const size_t idx);
Elf_Shdr *elf_get_sec_shstrtab(const Elf_Ehdr *ehdr); Elf_Shdr *elf_get_sec_shstrtab(const Elf_Ehdr *ehdr);
char *elf_get_shstrtab_str(const Elf_Ehdr *ehdr, size_t idx); 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, ...@@ -586,6 +589,7 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr,
const char *name, unsigned long *value); const char *name, unsigned long *value);
unsigned long elf_get_symbol_type(const Elf_Ehdr *ehdr, const char *name); 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, size_t elf_find_sec_idx_by_type(const Elf_Ehdr *ehdr,
const uint32_t sh_type, const uint32_t sh_type,
...@@ -606,4 +610,6 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr); ...@@ -606,4 +610,6 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr);
void elf_dump_sections(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_ */ #endif /* _KERNEL_ELF_H_ */
...@@ -62,7 +62,8 @@ struct elf_module { ...@@ -62,7 +62,8 @@ struct elf_module {
/* implemented in architecture code */ /* 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, struct module_section *find_mod_sec(const struct elf_module *m,
......
...@@ -69,6 +69,28 @@ struct module_section *find_mod_sec(const struct elf_module *m, ...@@ -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 * @brief setup the module structure
* *
...@@ -178,8 +200,13 @@ static int module_load_mem(struct elf_module *m) ...@@ -178,8 +200,13 @@ static int module_load_mem(struct elf_module *m)
sec = elf_get_sec_by_idx(m->ehdr, idx); sec = elf_get_sec_by_idx(m->ehdr, idx);
#if 0
if (!sec->sh_size) /* don't need those */ if (!sec->sh_size) /* don't need those */
continue; continue;
#else
if (!(sec->sh_flags & SHF_ALLOC))
continue;
#endif
s->size = sec->sh_size; s->size = sec->sh_size;
...@@ -194,20 +221,23 @@ static int module_load_mem(struct elf_module *m) ...@@ -194,20 +221,23 @@ static int module_load_mem(struct elf_module *m)
strcpy(s->name, src); 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) { 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, s->name, (char *) va_load,
sec->sh_size); sec->sh_size);
bzero((void *) va_load, s->size); bzero((void *) va_load, s->size);
} else { } 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, s->name,
(char *) m->ehdr + sec->sh_offset, (char *) m->ehdr + sec->sh_offset,
(char *) va_load, (char *) va_load,
sec->sh_size); sec->sh_size);
if (sec->sh_size)
memcpy((void *) va_load, memcpy((void *) va_load,
(char *) m->ehdr + sec->sh_offset, (char *) m->ehdr + sec->sh_offset,
sec->sh_size); sec->sh_size);
...@@ -219,11 +249,85 @@ static int module_load_mem(struct elf_module *m) ...@@ -219,11 +249,85 @@ static int module_load_mem(struct elf_module *m)
s++; s++;
if (s > &m->sec[m->num_sec]) { 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; 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; return 0;
error: error:
...@@ -264,11 +368,12 @@ static int module_relocate(struct elf_module *m) ...@@ -264,11 +368,12 @@ static int module_relocate(struct elf_module *m)
if (m->ehdr->e_type != ET_DYN) if (m->ehdr->e_type != ET_DYN)
return 0; return 0;
/* we only need RELA type relocations */ /* we only need RELA type relocations */
while (1) { while (1) {
char *rel_sec;
idx = elf_find_sec_idx_by_type(m->ehdr, SHT_RELA, idx + 1); idx = elf_find_sec_idx_by_type(m->ehdr, SHT_RELA, idx + 1);
if (!idx) if (!idx)
...@@ -276,8 +381,16 @@ static int module_relocate(struct elf_module *m) ...@@ -276,8 +381,16 @@ static int module_relocate(struct elf_module *m)
sec = elf_get_sec_by_idx(m->ehdr, idx); sec = elf_get_sec_by_idx(m->ehdr, idx);
pr_debug(MOD "\n" pr_info(MOD "\n"
MOD "Section Header info: %ld\n", sec->sh_info); 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) { if (sec) {
...@@ -295,7 +408,7 @@ static int module_relocate(struct elf_module *m) ...@@ -295,7 +408,7 @@ static int module_relocate(struct elf_module *m)
unsigned int symsec = ELF_R_SYM(relatab[i].r_info); unsigned int symsec = ELF_R_SYM(relatab[i].r_info);
char *symstr = elf_get_symbol_str(m->ehdr, symsec); char *symstr = elf_get_symbol_str(m->ehdr, symsec);
struct module_section *s; 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", pr_debug(MOD "OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n",
relatab[i].r_offset, relatab[i].r_offset,
...@@ -308,23 +421,63 @@ static int module_relocate(struct elf_module *m) ...@@ -308,23 +421,63 @@ static int module_relocate(struct elf_module *m)
if (strlen(symstr)) { if (strlen(symstr)) {
unsigned long symval;
Elf_Addr sym = (Elf_Addr) lookup_symbol(symstr); 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",
unsigned long symval;
pr_info(MOD "\tSymbol %s not found in library, trying to resolving in module\n",
symstr); symstr);
if ((elf_get_symbol_type(m->ehdr, symstr) & STT_OBJECT)) {
char *secstr;
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 (!(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);
} }
#if 0
if (!(elf_get_symbol_type(m->ehdr, symstr) & (STT_FUNC | STT_OBJECT))) { if (!(elf_get_symbol_type(m->ehdr, symstr) & (STT_FUNC | STT_OBJECT))) {
pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr);
return -1; return -1;
} }
#endif
if (!elf_get_symbol_value(m->ehdr, symstr, &symval)) { if (!elf_get_symbol_value(m->ehdr, symstr, &symval)) {
pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr);
return -1; return -1;
...@@ -334,25 +487,26 @@ static int module_relocate(struct elf_module *m) ...@@ -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 */ } else { /* no string, symtab entry is probably a section, try to identify it */
char *secstr = elf_get_shstrtab_str(m->ehdr, symsec); char *secstr = elf_get_shstrtab_str(m->ehdr, symsec);
s = find_mod_sec(m, secstr); s = find_mod_idx(m, symsec-1);
if (!s) { if (!s) {
pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr); pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr);
continue; continue;
} }
secstr = s->name;
/* target address to insert at location */ /* target address to insert at location */
reladdr = (long) s->addr; 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"); pr_debug(MOD "\n");
......
...@@ -510,6 +510,102 @@ unsigned long elf_get_symbol_value(const Elf_Ehdr *ehdr, ...@@ -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 * @brief get the ELF type of a symbol
* *
...@@ -607,7 +703,6 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr) ...@@ -607,7 +703,6 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr)
for (i = 0; i <ehdr->e_shnum; i++) { for (i = 0; i <ehdr->e_shnum; i++) {
shdr = elf_get_sec_by_idx(ehdr, i); shdr = elf_get_sec_by_idx(ehdr, i);
if ((shdr->sh_flags & SHF_ALLOC)) if ((shdr->sh_flags & SHF_ALLOC))
if (shdr->sh_size)
cnt++; cnt++;
} }
...@@ -615,6 +710,107 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr) ...@@ -615,6 +710,107 @@ size_t elf_get_num_alloc_sections(const Elf_Ehdr *ehdr)
} }
/* @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 * @brief get the number of entries in a dynamic section
* *
...@@ -727,7 +923,8 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr) ...@@ -727,7 +923,8 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr)
printk(MSG "\n" printk(MSG "\n"
MSG ".symtab contains %d entries\n" MSG ".symtab contains %d entries\n"
MSG "============================\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++) { for (i = 0; i < sym_cnt; i++) {
...@@ -756,7 +953,9 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr) ...@@ -756,7 +953,9 @@ void elf_dump_symtab(const Elf_Ehdr *ehdr)
printk("\tUNKNOWN"); break; 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);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment