forked from M-Labs/artiq
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:
parent
71b8575d7a
commit
3d8159ceb5
|
@ -74,15 +74,23 @@ struct elf32_sym {
|
||||||
unsigned short shndx; /* Section index of symbol. */
|
unsigned short shndx; /* Section index of symbol. */
|
||||||
} __attribute__((packed));
|
} __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) \
|
#define SANITIZE_OFFSET_SIZE(offset, size) \
|
||||||
if(offset > 0x10000000) { \
|
if(offset > 0x10000000) { \
|
||||||
printf("Incorrect offset in ELF data"); \
|
printf("Incorrect offset in ELF data"); \
|
||||||
return 0; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
if((offset + size) > elf_length) { \
|
if((offset + size) > elf_length) { \
|
||||||
printf("Attempted to access past the end of ELF data"); \
|
printf("Attempted to access past the end of ELF data"); \
|
||||||
return 0; \
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_POINTER_SAFE(target, target_type, offset) \
|
#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;
|
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_ehdr *ehdr;
|
||||||
struct elf32_shdr *strtable;
|
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 symtaboff, symtabsize;
|
||||||
unsigned int strtaboff, strtabsize;
|
unsigned int strtaboff, strtabsize;
|
||||||
|
|
||||||
|
void *entry_point;
|
||||||
|
|
||||||
|
|
||||||
/* validate ELF */
|
/* validate ELF */
|
||||||
GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0);
|
GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0);
|
||||||
if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
|
if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
|
||||||
printf("Incorrect ELF header\n");
|
printf("Incorrect ELF header\n");
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(ehdr->type != ET_REL) {
|
if(ehdr->type != ET_REL) {
|
||||||
printf("ELF is not relocatable\n");
|
printf("ELF is not relocatable\n");
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(ehdr->machine != EM_OR1K) {
|
if(ehdr->machine != EM_OR1K) {
|
||||||
printf("ELF is for a different machine\n");
|
printf("ELF is for a different machine\n");
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract section info */
|
/* extract section info */
|
||||||
|
@ -183,7 +193,7 @@ int load_elf(symbol_resolver resolver, void *elf_data, int elf_length, void *des
|
||||||
/* load .text section */
|
/* load .text section */
|
||||||
if(textsize > dest_length) {
|
if(textsize > dest_length) {
|
||||||
printf(".text section is too large\n");
|
printf(".text section is too large\n");
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
memcpy(dest, (char *)elf_data + textoff, textsize);
|
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)) {
|
for(i=0;i<textrelasize;i+=sizeof(struct elf32_rela)) {
|
||||||
struct elf32_rela *rela;
|
struct elf32_rela *rela;
|
||||||
struct elf32_sym *sym;
|
struct elf32_sym *sym;
|
||||||
char *name;
|
|
||||||
|
|
||||||
GET_POINTER_SAFE(rela, struct elf32_rela, textrelaoff + i);
|
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));
|
GET_POINTER_SAFE(sym, struct elf32_sym, symtaboff + sizeof(struct elf32_sym)*ELF32_R_SYM(rela->info));
|
||||||
if(sym->name != 0) {
|
if(sym->name != 0) {
|
||||||
|
char *name;
|
||||||
void *target;
|
void *target;
|
||||||
|
|
||||||
name = (char *)elf_data + strtaboff + sym->name;
|
name = (char *)elf_data + strtaboff + sym->name;
|
||||||
target = resolver(name);
|
target = resolver(name);
|
||||||
if(target == NULL) {
|
if(target == NULL) {
|
||||||
printf("Undefined symbol: %s\n", name);
|
printf("Undefined symbol: %s\n", name);
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(!fixup(dest, dest_length, rela, target))
|
if(!fixup(dest, dest_length, rela, target))
|
||||||
return 0;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
printf("Unsupported relocation\n");
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,6 @@ struct symbol {
|
||||||
void *find_symbol(const struct symbol *symbols, const char *name);
|
void *find_symbol(const struct symbol *symbols, const char *name);
|
||||||
|
|
||||||
typedef void * (*symbol_resolver)(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 */
|
#endif /* __ELF_LOADER_H */
|
||||||
|
|
|
@ -15,7 +15,7 @@ int main(void)
|
||||||
{
|
{
|
||||||
unsigned char kbuf[256*1024];
|
unsigned char kbuf[256*1024];
|
||||||
unsigned char kcode[256*1024];
|
unsigned char kcode[256*1024];
|
||||||
kernel_function k = (kernel_function)kcode;
|
kernel_function k;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
irq_setmask(0);
|
irq_setmask(0);
|
||||||
|
@ -27,7 +27,8 @@ int main(void)
|
||||||
while(1) {
|
while(1) {
|
||||||
length = ident_and_download_kernel(kbuf, sizeof(kbuf));
|
length = ident_and_download_kernel(kbuf, sizeof(kbuf));
|
||||||
if(length > 0) {
|
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();
|
rtio_init();
|
||||||
dds_init();
|
dds_init();
|
||||||
flush_cpu_icache();
|
flush_cpu_icache();
|
||||||
|
|
Loading…
Reference in New Issue