soc/runtime: find ELF entry point

This allows multiple functions to be defined, with the main one not necessarily starting at 0.
This commit is contained in:
Sebastien Bourdeauducq 2014-09-07 17:29:48 +08:00
parent 71b8575d7a
commit 3d8159ceb5
3 changed files with 45 additions and 15 deletions

View File

@ -74,15 +74,23 @@ struct elf32_sym {
unsigned short shndx; /* Section index of symbol. */
} __attribute__((packed));
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define ELF32_ST_TYPE(info) ((info) & 0x0f)
#define SANITIZE_OFFSET_SIZE(offset, size) \
if(offset > 0x10000000) { \
printf("Incorrect offset in ELF data"); \
return 0; \
return NULL; \
} \
if((offset + size) > elf_length) { \
printf("Attempted to access past the end of ELF data"); \
return 0; \
return NULL; \
}
#define GET_POINTER_SAFE(target, target_type, offset) \
@ -117,7 +125,7 @@ static int fixup(void *dest, int dest_length, struct elf32_rela *rela, void *tar
return 1;
}
int load_elf(symbol_resolver resolver, void *elf_data, int elf_length, void *dest, int dest_length)
void *load_elf(symbol_resolver resolver, const char *entry_name, void *elf_data, int elf_length, void *dest, int dest_length)
{
struct elf32_ehdr *ehdr;
struct elf32_shdr *strtable;
@ -129,20 +137,22 @@ int load_elf(symbol_resolver resolver, void *elf_data, int elf_length, void *des
unsigned int symtaboff, symtabsize;
unsigned int strtaboff, strtabsize;
void *entry_point;
/* validate ELF */
GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0);
if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
printf("Incorrect ELF header\n");
return 0;
return NULL;
}
if(ehdr->type != ET_REL) {
printf("ELF is not relocatable\n");
return 0;
return NULL;
}
if(ehdr->machine != EM_OR1K) {
printf("ELF is for a different machine\n");
return 0;
return NULL;
}
/* extract section info */
@ -183,7 +193,7 @@ int load_elf(symbol_resolver resolver, void *elf_data, int elf_length, void *des
/* load .text section */
if(textsize > dest_length) {
printf(".text section is too large\n");
return 0;
return NULL;
}
memcpy(dest, (char *)elf_data + textoff, textsize);
@ -191,26 +201,45 @@ int load_elf(symbol_resolver resolver, void *elf_data, int elf_length, void *des
for(i=0;i<textrelasize;i+=sizeof(struct elf32_rela)) {
struct elf32_rela *rela;
struct elf32_sym *sym;
char *name;
GET_POINTER_SAFE(rela, struct elf32_rela, textrelaoff + i);
GET_POINTER_SAFE(sym, struct elf32_sym, symtaboff + sizeof(struct elf32_sym)*ELF32_R_SYM(rela->info));
if(sym->name != 0) {
char *name;
void *target;
name = (char *)elf_data + strtaboff + sym->name;
target = resolver(name);
if(target == NULL) {
printf("Undefined symbol: %s\n", name);
return 0;
return NULL;
}
if(!fixup(dest, dest_length, rela, target))
return 0;
return NULL;
} else {
printf("Unsupported relocation\n");
return 0;
return NULL;
}
}
return 1;
/* find entry point */
entry_point = NULL;
for(i=0;i<symtabsize;i+=sizeof(struct elf32_sym)) {
struct elf32_sym *sym;
GET_POINTER_SAFE(sym, struct elf32_sym, symtaboff + i);
if((ELF32_ST_TYPE(sym->info) == STT_FUNC) && (sym->name != 0)) {
char *name;
name = (char *)elf_data + strtaboff + sym->name;
if(strcmp(name, entry_name) == 0) {
entry_point = (char *)dest + sym->value;
break;
}
}
}
if(entry_point == NULL)
printf("Failed to find entry point\n");
return entry_point;
}

View File

@ -9,6 +9,6 @@ struct symbol {
void *find_symbol(const struct symbol *symbols, const char *name);
typedef void * (*symbol_resolver)(const char *name);
int load_elf(symbol_resolver resolver, void *elf_data, int elf_length, void *dest, int dest_length);
void *load_elf(symbol_resolver resolver, const char *entry_name, void *elf_data, int elf_length, void *dest, int dest_length);
#endif /* __ELF_LOADER_H */

View File

@ -15,7 +15,7 @@ int main(void)
{
unsigned char kbuf[256*1024];
unsigned char kcode[256*1024];
kernel_function k = (kernel_function)kcode;
kernel_function k;
int length;
irq_setmask(0);
@ -27,7 +27,8 @@ int main(void)
while(1) {
length = ident_and_download_kernel(kbuf, sizeof(kbuf));
if(length > 0) {
if(load_elf(resolve_symbol, kbuf, length, kcode, sizeof(kcode))) {
k = load_elf(resolve_symbol, "run", kbuf, length, kcode, sizeof(kcode));
if(k != NULL) {
rtio_init();
dds_init();
flush_cpu_icache();