Removed old elfloader.c and replaced with the current code (previously in elfloader-tmp.c)

This commit is contained in:
adamdunkels 2006-12-18 11:55:42 +00:00
parent 5d3baef0d2
commit 70170b65b6

View file

@ -28,46 +28,30 @@
* *
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
* @(#)$Id: elfloader.c,v 1.1 2006/06/17 22:41:18 adamdunkels Exp $ * @(#)$Id: elfloader.c,v 1.2 2006/12/18 11:55:42 adamdunkels Exp $
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/unistd.h>
#include "contiki.h" #include "contiki.h"
#include "loader/elfloader.h" #include "loader/elfloader-tmp.h"
#include "loader/elfloader-arch.h"
#include "cfs/cfs.h"
#include "loader/symtab.h" #include "loader/symtab.h"
#include "lib/malloc.h" #include <stddef.h>
#include "dev/rom.h" #include <string.h>
#include "dev/xmem.h" #include <stdio.h>
#if 0 #if 0
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__) #define PRINTF(...) printf(__VA_ARGS__)
#else #else
#define PRINTF(...) do {} while (0) #define PRINTF(...) do {} while (0)
#endif #endif
#define IMAX(a, b) (((a) > (b)) ? (a) : (b))
static char *datamemory;
#define TEXTADDRESS \
(((uintptr_t)&_etext + (uintptr_t)&_edata - (uintptr_t)&__data_start \
+ ROM_ERASE_UNIT_SIZE) & ~(ROM_ERASE_UNIT_SIZE - 1))
#define EI_NIDENT 16 #define EI_NIDENT 16
typedef unsigned long elf32_word;
typedef signed long elf32_sword;
typedef unsigned short elf32_half;
typedef unsigned long elf32_off;
typedef unsigned long elf32_addr;
struct elf32_ehdr { struct elf32_ehdr {
unsigned char e_ident[EI_NIDENT]; /* ident bytes */ unsigned char e_ident[EI_NIDENT]; /* ident bytes */
@ -129,12 +113,6 @@ struct elf32_rel {
elf32_word r_info; /* Relocation type and symbol index. */ elf32_word r_info; /* Relocation type and symbol index. */
}; };
struct elf32_rela {
elf32_addr r_offset; /* Location to be relocated. */
elf32_word r_info; /* Relocation type and symbol index. */
elf32_sword r_addend; /* Addend. */
};
struct elf32_sym { struct elf32_sym {
elf32_word st_name; /* String table index of name. */ elf32_word st_name; /* String table index of name. */
elf32_addr st_value; /* Symbol value. */ elf32_addr st_value; /* Symbol value. */
@ -149,45 +127,118 @@ struct elf32_sym {
struct relevant_section { struct relevant_section {
unsigned char number; unsigned char number;
//off_t offset; unsigned int offset;
char *address; char *address;
}; };
char elfloader_unknown[30]; /* Name that caused link error. */ char elfloader_unknown[30]; /* Name that caused link error. */
struct process **elfloader_autostart_processes;
static struct relevant_section bss, data, text; static struct relevant_section bss, data, text;
/*static unsigned char bss_sectionno, data_sectionno, text_sectionno;*/ const static unsigned char elf_magic_header[] =
static const unsigned char elf_magic_header[] =
{0x7f, 0x45, 0x4c, 0x46, /* 0x7f, 'E', 'L', 'F' */ {0x7f, 0x45, 0x4c, 0x46, /* 0x7f, 'E', 'L', 'F' */
0x01, /* Only 32-bit objects. */ 0x01, /* Only 32-bit objects. */
0x01, /* Only LSB data. */ 0x01, /* Only LSB data. */
0x01, /* Only ELF version 1. */ 0x01, /* Only ELF version 1. */
}; };
/*---------------------------------------------------------------------------*/
static void
seek_read(int fd, unsigned int offset, char *buf, int len)
{
cfs_seek(fd, offset);
cfs_read(fd, buf, len);
}
/*---------------------------------------------------------------------------*/
/*
static void
seek_write(int fd, unsigned int offset, char *buf, int len)
{
cfs_seek(fd, offset);
cfs_write(fd, buf, len);
}
*/
/*---------------------------------------------------------------------------*/
static void *
find_local_symbol(int fd, const char *symbol,
unsigned int symtab, unsigned short symtabsize,
unsigned int strtab)
{
struct elf32_sym s;
unsigned int a;
char name[30];
struct relevant_section *sect;
for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) {
seek_read(fd, a, (char *)&s, sizeof(s));
if(s.st_name != 0) {
seek_read(fd, strtab + s.st_name, name, sizeof(name));
if(strcmp(name, symbol) == 0) {
if(s.st_shndx == bss.number) {
sect = &bss;
} else if(s.st_shndx == data.number) {
sect = &data;
} else if(s.st_shndx == text.number) {
sect = &text;
} else {
return NULL;
}
return &(sect->address[s.st_value]);
}
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
relocate_section(off_t section, unsigned short size, relocate_section(int fd,
off_t sectionaddr, unsigned int section, unsigned short size,
off_t strs, unsigned int sectionaddr,
off_t strtab, unsigned int strs,
off_t symtab, unsigned int strtab,
char *mem) unsigned int symtab, unsigned short symtabsize)
{ {
struct elf32_rela rela; struct elf32_rela rela;
struct elf32_sym s; struct elf32_sym s;
off_t a; unsigned int a;
char name[30]; char name[30];
char *addr; char *addr;
struct relevant_section *sect; struct relevant_section *sect;
for(a = section; a < section + size; a += sizeof(struct elf32_rela)) { for(a = section; a < section + size; a += sizeof(struct elf32_rela)) {
xmem_pread(&rela, sizeof(rela), a); seek_read(fd, a, (char *)&rela, sizeof(rela));
xmem_pread(&s, sizeof(s), seek_read(fd,
symtab + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info)); symtab + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info),
if(s.st_name == 0) { /* Local symbol (static) */ (char *)&s, sizeof(s));
if(s.st_name != 0) {
seek_read(fd, strtab + s.st_name, name, sizeof(name));
PRINTF("name: %s\n", name);
addr = (char *)symtab_lookup(name);
/* ADDED */
if(addr == NULL) {
PRINTF("name not found in global: %s\n", name);
addr = find_local_symbol(fd, name, symtab, symtabsize, strtab);
PRINTF("found address %p\n", addr);
}
if(addr == NULL) {
if(s.st_shndx == bss.number) {
sect = &bss;
} else if(s.st_shndx == data.number) {
sect = &data;
} else if(s.st_shndx == text.number) {
sect = &text;
} else {
PRINTF("elfloader unknown name: '%30s'\n", name);
memcpy(elfloader_unknown, name, sizeof(elfloader_unknown));
elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0;
return ELFLOADER_SYMBOL_NOT_FOUND;
}
addr = sect->address;
}
} else {
if(s.st_shndx == bss.number) { if(s.st_shndx == bss.number) {
sect = &bss; sect = &bss;
} else if(s.st_shndx == data.number) { } else if(s.st_shndx == data.number) {
@ -197,77 +248,70 @@ relocate_section(off_t section, unsigned short size,
} else { } else {
return ELFLOADER_SEGMENT_NOT_FOUND; return ELFLOADER_SEGMENT_NOT_FOUND;
} }
addr = sect->address + rela.r_addend;
} else { addr = sect->address;
xmem_pread(name, sizeof(name), strtab + s.st_name);
addr = (char *)symtab_lookup(name);
if(addr != NULL) { /* Global symbol */
addr += rela.r_addend;
} else { /* Exported symbol */
if(s.st_shndx == bss.number) {
sect = &bss;
} else if(s.st_shndx == data.number) {
sect = &data;
} else if(s.st_shndx == text.number) {
sect = &text;
} else {
PRINTF("elfloader unkown name: '%30s'\n", name);
memcpy(elfloader_unknown, name, sizeof(elfloader_unknown));
elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0;
return ELFLOADER_SYMBOL_NOT_FOUND;
} }
addr = sect->address + s.st_value + rela.r_addend;
} elfloader_arch_relocate(fd, sectionaddr, &rela, addr);
}
memcpy(&mem[rela.r_offset], &addr, 2); /* Write reloc */
} }
return ELFLOADER_OK; return ELFLOADER_OK;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
typedef void (*PFV)(void); static void *
find_program_processes(int fd,
struct process *elfloader_loaded_process; unsigned int symtab, unsigned short size,
void (*elfloader_fini)(void); unsigned int strtab)
static PFV
find_init_and_fini(off_t symtab, unsigned short size, off_t strtab)
{ {
struct elf32_sym s; struct elf32_sym s;
off_t a; unsigned int a;
char name[30]; char name[30];
void (*elfloader_init)(void);
elfloader_init = NULL;
for(a = symtab; a < symtab + size; a += sizeof(s)) { for(a = symtab; a < symtab + size; a += sizeof(s)) {
xmem_pread(&s, sizeof(s), a); seek_read(fd, a, (char *)&s, sizeof(s));
if(s.st_name != 0) { if(s.st_name != 0) {
xmem_pread(name, sizeof(name), strtab + s.st_name); seek_read(fd, strtab + s.st_name, name, sizeof(name));
if(strcmp(name, "process_load") == 0) { if(strcmp(name, "autostart_processes") == 0) {
elfloader_loaded_process = return &data.address[s.st_value];
*(struct process **)&data.address[s.st_value];
} else if (strcmp(name, "_init") == 0) {
/* XXX Check segment == text. */
elfloader_init = (PFV)&text.address[s.st_value];
} else if (strcmp(name, "_fini") == 0) {
/* XXX Check segment == text. */
elfloader_fini = (PFV)&text.address[s.st_value];
} }
} }
} }
return elfloader_init; return NULL;
/* return find_local_symbol(fd, "autostart_processes", symtab, size, strtab); */
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void
elfloader_init(void)
{
elfloader_autostart_processes = NULL;
}
/*---------------------------------------------------------------------------*/
#if 0
static void
print_chars(unsigned char *ptr, int num)
{
int i;
for(i = 0; i < num; ++i) {
PRINTF("%d", ptr[i]);
if(i == num - 1) {
PRINTF("\n");
} else {
PRINTF(", ");
}
}
}
#endif /* 0 */
/*---------------------------------------------------------------------------*/
int int
elfloader_load(off_t eepromaddr) elfloader_load(int fd)
{ {
struct elf32_ehdr ehdr; struct elf32_ehdr ehdr;
struct elf32_shdr shdr; struct elf32_shdr shdr;
struct elf32_shdr strtable; struct elf32_shdr strtable;
off_t strs; unsigned int strs;
off_t shdrptr; unsigned int shdrptr;
off_t nameptr; unsigned int nameptr;
char name[12]; char name[12];
int i; int i;
@ -279,35 +323,38 @@ elfloader_load(off_t eepromaddr)
unsigned short strtaboff = 0, strtabsize; unsigned short strtaboff = 0, strtabsize;
unsigned short bsssize = 0; unsigned short bsssize = 0;
struct process **process;
int ret; int ret;
void (*elfloader_init)(void);
elfloader_unknown[0] = 0; elfloader_unknown[0] = 0;
/* The ELF header is located at the start of the buffer. */ /* The ELF header is located at the start of the buffer. */
xmem_pread(&ehdr, sizeof(ehdr), eepromaddr); seek_read(fd, 0, (char *)&ehdr, sizeof(ehdr));
/* print_chars(ehdr.e_ident, sizeof(elf_magic_header));
print_chars(elf_magic_header, sizeof(elf_magic_header));*/
/* Make sure that we have a correct and compatible ELF header. */ /* Make sure that we have a correct and compatible ELF header. */
if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) { if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
PRINTF("ELF header problems\n");
return ELFLOADER_BAD_ELF_HEADER; return ELFLOADER_BAD_ELF_HEADER;
} }
/* Grab the section header. */ /* Grab the section header. */
shdrptr = eepromaddr + ehdr.e_shoff; shdrptr = ehdr.e_shoff;
xmem_pread(&shdr, sizeof(shdr), shdrptr); seek_read(fd, shdrptr, (char *)&shdr, sizeof(shdr));
/* Get the size and number of entries of the section header. */ /* Get the size and number of entries of the section header. */
shdrsize = ehdr.e_shentsize; shdrsize = ehdr.e_shentsize;
shdrnum = ehdr.e_shnum; shdrnum = ehdr.e_shnum;
/* The string table section: holds the names of the sections. */ /* The string table section: holds the names of the sections. */
xmem_pread(&strtable, sizeof(strtable), seek_read(fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx,
eepromaddr + ehdr.e_shoff + shdrsize * ehdr.e_shstrndx); (char *)&strtable, sizeof(strtable));
/* Get a pointer to the actual table of strings. This table holds /* Get a pointer to the actual table of strings. This table holds
the names of the sections, not the names of other symbols in the the names of the sections, not the names of other symbols in the
file (these are in the sybtam section). */ file (these are in the sybtam section). */
strs = eepromaddr + strtable.sh_offset; strs = strtable.sh_offset;
/* Go through all sections and pick out the relevant ones. The /* Go through all sections and pick out the relevant ones. The
".text" segment holds the actual code from the ELF file, the ".text" segment holds the actual code from the ELF file, the
@ -332,14 +379,14 @@ elfloader_load(off_t eepromaddr)
bss.number = data.number = text.number = 0; bss.number = data.number = text.number = 0;
shdrptr = eepromaddr + ehdr.e_shoff; shdrptr = ehdr.e_shoff;
for(i = 0; i < shdrnum; ++i) { for(i = 0; i < shdrnum; ++i) {
xmem_pread(&shdr, sizeof(shdr), shdrptr); seek_read(fd, shdrptr, (char *)&shdr, sizeof(shdr));
/* The name of the section is contained in the strings table. */ /* The name of the section is contained in the strings table. */
nameptr = strs + shdr.sh_name; nameptr = strs + shdr.sh_name;
xmem_pread(name, sizeof(name), nameptr); seek_read(fd, nameptr, name, sizeof(name));
/* Match the name of the section with a predefined set of names /* Match the name of the section with a predefined set of names
(.text, .data, .bss, .rela.text, .rela.data, .symtab, and (.text, .data, .bss, .rela.text, .rela.data, .symtab, and
@ -349,7 +396,7 @@ elfloader_load(off_t eepromaddr)
textoff = shdr.sh_offset; textoff = shdr.sh_offset;
textsize = shdr.sh_size; textsize = shdr.sh_size;
text.number = i; text.number = i;
//text.offset = eepromaddr + textoff; text.offset = textoff;
} else if(strncmp(name, ".rela.text", 10) == 0) { } else if(strncmp(name, ".rela.text", 10) == 0) {
textrelaoff = shdr.sh_offset; textrelaoff = shdr.sh_offset;
textrelasize = shdr.sh_size; textrelasize = shdr.sh_size;
@ -357,7 +404,7 @@ elfloader_load(off_t eepromaddr)
dataoff = shdr.sh_offset; dataoff = shdr.sh_offset;
datasize = shdr.sh_size; datasize = shdr.sh_size;
data.number = i; data.number = i;
//data.offset = eepromaddr + dataoff; data.offset = dataoff;
} else if(strncmp(name, ".rela.data", 10) == 0) { } else if(strncmp(name, ".rela.data", 10) == 0) {
datarelaoff = shdr.sh_offset; datarelaoff = shdr.sh_offset;
datarelasize = shdr.sh_size; datarelasize = shdr.sh_size;
@ -370,16 +417,13 @@ elfloader_load(off_t eepromaddr)
} else if(strncmp(name, ".bss", 4) == 0) { } else if(strncmp(name, ".bss", 4) == 0) {
bsssize = shdr.sh_size; bsssize = shdr.sh_size;
bss.number = i; bss.number = i;
//bss.offset = 0; bss.offset = 0;
} else {
PRINTF("elfloader: unknown '%12s' %d\n", name, shdrsize);
} }
/* Move on to the next section header. */ /* Move on to the next section header. */
shdrptr += shdrsize; shdrptr += shdrsize;
} }
if(symtabsize == 0) { if(symtabsize == 0) {
return ELFLOADER_NO_SYMTAB; return ELFLOADER_NO_SYMTAB;
} }
@ -390,102 +434,60 @@ elfloader_load(off_t eepromaddr)
return ELFLOADER_NO_TEXT; return ELFLOADER_NO_TEXT;
} }
if(datamemory != NULL) { bss.address = (char *)elfloader_arch_allocate_ram(bsssize + datasize);
free(datamemory); data.address = (char *)bss.address + bsssize;
} text.address = (char *)elfloader_arch_allocate_rom(textsize);
/* We are making semi-permanent allocations, first compact heap! */
malloc_compact();
datamemory = malloc(IMAX(textsize, datasize + bsssize));
if(datamemory == NULL) {
return ELFLOADER_DATA_TO_LARGE; /* XXX or text to large */
}
bss.address = (char *)datamemory; /* If we have text segment relocations, we process them. */
data.address = (char *)datamemory + bsssize; PRINTF("elfloader: relocate text\n");
text.address = (char *)TEXTADDRESS;
PRINTF("elfloader: copy text segment to RAM %p %p\n",
datamemory, datamemory + textsize);
xmem_pread(datamemory, textsize, eepromaddr + textoff);
if(textrelasize > 0) { if(textrelasize > 0) {
PRINTF("elfloader: relocate text in RAM\n"); ret = relocate_section(fd,
ret = relocate_section(eepromaddr + textrelaoff, textrelasize, textrelaoff, textrelasize,
eepromaddr + textoff, textoff,
strs, strs,
eepromaddr + strtaboff, strtaboff,
eepromaddr + symtaboff, symtaboff, symtabsize);
datamemory);
if(ret != ELFLOADER_OK) { if(ret != ELFLOADER_OK) {
return ret; return ret;
} }
} }
PRINTF("elfloader: copy text segment to ROM %p %p\n",
text.address, text.address + textsize);
rom_erase((textsize + ROM_ERASE_UNIT_SIZE) & ~(ROM_ERASE_UNIT_SIZE - 1),
(uintptr_t)text.address);
rom_pwrite(datamemory, textsize, (uintptr_t)text.address);
PRINTF("elfloader: copy data segment to RAM %p %p\n", /* If we have any data segment relocations, we process them too. */
data.address, data.address + datasize); PRINTF("elfloader: relocate data\n");
xmem_pread(data.address, datasize, eepromaddr + dataoff);
if(datarelasize > 0) { if(datarelasize > 0) {
PRINTF("elfloader: relocate data segment\n"); ret = relocate_section(fd,
ret = relocate_section(eepromaddr + datarelaoff, datarelasize, datarelaoff, datarelasize,
eepromaddr + dataoff, dataoff,
strs, strs,
eepromaddr + strtaboff, strtaboff,
eepromaddr + symtaboff, symtaboff, symtabsize);
data.address);
if(ret != ELFLOADER_OK) { if(ret != ELFLOADER_OK) {
PRINTF("elfloader: data failed\n");
return ret; return ret;
} }
} }
PRINTF("elfloader: zero bss %p %p\n", bss.address, bss.address + bsssize); /* Write text segment into flash and data segment into RAM. */
cfs_seek(fd, textoff);
elfloader_arch_write_text(fd, textsize, text.address);
memset(bss.address, 0, bsssize); memset(bss.address, 0, bsssize);
datamemory = realloc(datamemory, datasize + bsssize); seek_read(fd, dataoff, data.address, datasize);
if(datamemory != bss.address) {
free(bss.address);
return ELFLOADER_BSS_TO_LARGE; /* XXX realloc moved data */
}
/* Find _init, _fini, and loaded_process. */ PRINTF("elfloader: autostart search\n");
elfloader_loaded_process = NULL; process = find_local_symbol(fd, "autostart_processes", symtaboff, symtabsize, strtaboff);
elfloader_fini = NULL; if(process != NULL) {
elfloader_init = find_init_and_fini(eepromaddr + symtaboff, PRINTF("elfloader: autostart found\n");
symtabsize, elfloader_autostart_processes = process;
eepromaddr + strtaboff);
if(elfloader_init != NULL) {
PRINTF("init=%p fini=%p\n", elfloader_init, elfloader_fini);
(*elfloader_init)();
elfloader_loaded_process = NULL;
return ELFLOADER_OK;
}
if(elfloader_loaded_process != NULL) {
PRINTF("elfloader: launch program\n");
process_start(elfloader_loaded_process, NULL);
elfloader_fini = NULL;
return ELFLOADER_OK; return ELFLOADER_OK;
} else { } else {
PRINTF("elfloader: no autostart\n");
process = find_program_processes(fd, symtaboff, symtabsize, strtaboff);
if(process != NULL) {
PRINTF("elfloader: FOUND PRG\n");
}
return ELFLOADER_NO_STARTPOINT; return ELFLOADER_NO_STARTPOINT;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void
elfloader_unload(void)
{
if(elfloader_fini != NULL) {
(*elfloader_fini)();
elfloader_fini = NULL;
} else if(elfloader_loaded_process != NULL) {
process_exit(elfloader_loaded_process);
elfloader_loaded_process = NULL;
}
if(datamemory != NULL) {
free(datamemory);
datamemory = NULL;
}
}