diff --git a/core/loader/cle.c b/core/loader/cle.c new file mode 100644 index 000000000..5f5c4bd6e --- /dev/null +++ b/core/loader/cle.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)$Id: cle.c,v 1.1 2006/12/01 15:12:27 bg- Exp $ + */ + +/* + * The Contiki dynamic Link Editor (CLE), ELF version. + */ + +#include +#include + +#include "contiki.h" + +#include "loader/cle.h" +#include "loader/elf32.h" +#include "loader/symtab.h" + +#define NDEBUG +#include "lib/assert.h" + +#ifdef NDEBUG +#define PRINTF(...) do {} while (0) +#else +#define PRINTF(...) printf(__VA_ARGS__) +#endif + +/* + * Parse object file located at offset start reading data using function + * pread. Save what is useful in info. + */ +int +cle_read_info(struct cle_info *info, + int (*pread)(void *, int, off_t), + off_t start) +{ + /* + * Save stackspace by using a union! + * + * Beware that the contents of ehdr is gone when shdr is written!!! + */ + union { + struct elf32_ehdr ehdr; + struct elf32_shdr shdr; + } huge; +#define ehdr huge.ehdr +#define shdr huge.shdr + + off_t shdrptr; + cle_off strs; + cle_half shnum; /* number shdrs */ + cle_half shentsize; /* sizeof shdr */ + cle_word strtabsize = 0; + int i, ret; + + memset(info, 0x0, sizeof(*info)); + + ret = pread(&ehdr, sizeof(ehdr), start); + assert(ret > 0); + + /* Make sure that we have a correct and compatible ELF header. */ + if(memcmp(ehdr.e_ident, ELF_MAGIC_HEADER, ELF_MAGIC_HEADER_SIZE) != 0) { + return CLE_BAD_HEADER; + } + + shdrptr = ehdr.e_shoff; + shentsize = ehdr.e_shentsize; + shnum = ehdr.e_shnum; + + /* The string table section: holds the names of the sections. */ + ret = pread(&shdr, sizeof(shdr), start + shdrptr + shentsize*ehdr.e_shstrndx); + assert(ret > 0); + + /* BEWARE THAT ehdr IS NOW OVERWRITTEN!!! */ + + /* + * 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 + * file (these are in the symtab section). + */ + strs = shdr.sh_offset; + + /* + * The ".text" segment holds the actual code from the ELF file, the + * ".data" segment contains initialized data, the ".bss" segment + * holds the size of the unitialized data segment. The ".rela.text" + * and ".rela.data" segments contains relocation information for the + * contents of the ".text" and ".data" segments, respectively. The + * ".symtab" segment contains the symbol table for this file. The + * ".strtab" segment points to the actual string names used by the + * symbol table. + * + * In addition to grabbing pointers to the relevant sections, we + * also save the section index for resolving addresses in the + * relocator code. + */ + for(i = 0; i < shnum; ++i) { + ret = pread(&shdr, sizeof(shdr), shdrptr); + assert(ret > 0); + + /* The name of the section is contained in the strings table. */ + ret = pread(info->name, sizeof(info->name), start + strs + shdr.sh_name); + assert(ret > 0); + + if(strncmp(info->name, ".text", 5) == 0) { + info->textoff = shdr.sh_offset; + info->textsize = shdr.sh_size; + info->text_shndx = i; + } else if(strncmp(info->name, ".rela.text", 10) == 0) { + info->textrelaoff = shdr.sh_offset; + info->textrelasize = shdr.sh_size; + } else if(strncmp(info->name, ".data", 5) == 0) { + info->dataoff = shdr.sh_offset; + info->datasize = shdr.sh_size; + info->data_shndx = i; + } else if(strncmp(info->name, ".rela.data", 10) == 0) { + info->datarelaoff = shdr.sh_offset; + info->datarelasize = shdr.sh_size; + } else if(strncmp(info->name, ".symtab", 7) == 0) { + info->symtaboff = shdr.sh_offset; + info->symtabsize = shdr.sh_size; + } else if(strncmp(info->name, ".strtab", 7) == 0) { + info->strtaboff = shdr.sh_offset; + strtabsize = shdr.sh_size; + } else if(strncmp(info->name, ".bss", 4) == 0) { + info->bsssize = shdr.sh_size; + info->bss_shndx = i; + } else { + info->name[sizeof(info->name) - 1] = 0; + PRINTF("cle: unknown section %.12s\n", info->name); + } + + /* Move on to the next section header. */ + shdrptr += shentsize; + } + + if(info->symtabsize == 0) { + return CLE_NO_SYMTAB; + } + if(strtabsize == 0) { + return CLE_NO_STRTAB; + } + if(info->textsize == 0) { + return CLE_NO_TEXT; + } + + return CLE_OK; +} + +/* + * Update one reloc. + * + * Writing relocs is machine dependent and this function is MPS430 + * specific! + */ +static inline int +cle_upd_reloc(cle_addr segmem, struct elf32_rela *rela, cle_addr addr) +{ + memcpy(segmem + rela->r_offset, &addr, 2); /* Write reloc */ + return 0; +} + +/* + * Relocate one segment that has been copied to the location pointed + * to by segmem. + * + * Relocation info is read from offset reloff to (reloff + relsize) + * and the start of the object file is at start. Data is read using + * function pread. + */ +int +cle_relocate(struct cle_info *info, + int (*pread)(void *, int, off_t), + off_t start, /* Offset to start of file. */ + cle_addr segmem, /* Where segment is stored in memory. */ + cle_off reloff, /* .rela. start */ + cle_word relsize) /* .rela. size */ +{ + struct elf32_rela rela; + struct elf32_sym s; + off_t off; + cle_addr addr; + int ret; + + for(off = start + reloff; + off < start + reloff + relsize; + off += sizeof(struct elf32_rela)) { + ret = pread(&rela, sizeof(rela), off); + assert(ret > 0); + ret = pread(&s, sizeof(s), + start + info->symtaboff + + sizeof(struct elf32_sym)*ELF32_R_SYM(rela.r_info)); + assert(ret > 0); + + if(s.st_shndx == info->bss_shndx) { + addr = info->bss; + } else if(s.st_shndx == info->data_shndx) { + addr = info->data; + } else if(s.st_shndx == info->text_shndx) { + addr = info->text; + } else { + addr = NULL; + } + + if(s.st_name == 0) { /* No name, local symbol? */ + if(addr == NULL) { + return CLE_UNKNOWN_SEGMENT; + } + } else { + ret = pread(info->name, sizeof(info->name), + start + info->strtaboff + s.st_name); + assert(ret > 0); + cle_addr sym = symtab_lookup(info->name); + + if(addr == NULL && sym != NULL) { /* Imported symbol. */ + addr = sym; + } else if(addr != NULL && sym == NULL) { /* Exported symbol. */ + addr = addr + s.st_value; + } else if(addr == NULL && sym == NULL) { + PRINTF("cle: undefined reference to %.32s\n", info->name); + return CLE_UNDEFINED; /* Or COMMON symbol. */ + } else if(addr != NULL && sym != NULL) { + PRINTF("cle: multiple definitions of %.32s\n", info->name); + return CLE_MULTIPLY_DEFINED; + } + } + + addr += rela.r_addend; + + cle_upd_reloc(segmem, &rela, addr); + } + return CLE_OK; +} + +/* + * Search object file located at offset start using function + * pread. Search for symbol named symbol and return its address after + * relocation or NULL on failure. + */ +void * +cle_lookup(struct cle_info *info, + int (*pread)(void *, int, off_t), + off_t start, /* Offset to start of file. */ + const char *symbol) + +{ + struct elf32_sym s; + off_t a; + cle_addr addr; + int ret; + + for(a = start + info->symtaboff; + a < start + info->symtaboff + info->symtabsize; + a += sizeof(s)) { + ret = pread(&s, sizeof(s), a); + assert(ret > 0); + + if(s.st_name != 0) { + ret = pread(info->name, sizeof(info->name), + start + info->strtaboff + s.st_name); + assert(ret > 0); + + if(strcmp(info->name, symbol) == 0) { /* Exported symbol found. */ + if(s.st_shndx == info->bss_shndx) { + addr = info->bss; + } else if(s.st_shndx == info->data_shndx) { + addr = info->data; + } else if(s.st_shndx == info->text_shndx) { + addr = info->text; + } else { + return NULL; /* Really an error! */ + } + return addr + s.st_value; + } + } + } + return NULL; +} diff --git a/core/loader/cle.h b/core/loader/cle.h new file mode 100644 index 000000000..6892ed9fa --- /dev/null +++ b/core/loader/cle.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)$Id: cle.h,v 1.1 2006/12/01 15:12:27 bg- Exp $ + */ + +#ifndef CLE_H +#define CLE_H + +/* + * The Contiki dynamic Link Editor (CLE) for small systems. + */ + +/* These typedefs limits object file size! */ +typedef u16_t cle_off; /* Offset from start of file. */ +typedef u16_t cle_word; +typedef u16_t cle_half; + +/* Also used for address arithmetic (can't be void *). */ +typedef unsigned char *cle_addr; +/* typedef uintptr_t cle_addr; */ + +struct cle_info { + cle_addr text, data, bss; + + cle_off textrelaoff, datarelaoff; + cle_word textrelasize, datarelasize; + + cle_off textoff, dataoff; + cle_word textsize, datasize, bsssize; + + cle_off symtaboff, strtaboff; + cle_word symtabsize; + + unsigned char text_shndx; + unsigned char data_shndx; + unsigned char bss_shndx; + unsigned char unused_shndx; + + char name[32]; /* Scratch and errmsg buffer. */ +}; + +int +cle_read_info(struct cle_info *info, + int (*read)(void *, int, off_t), + off_t hdr); /* Offset to start of file. */ + +int +cle_relocate(struct cle_info *info, + int (*read)(void *, int, off_t), + off_t hdr, /* Offset to start of file. */ + cle_addr segmem, /* Where segment is stored in memory. */ + cle_off reloff, /* .rela. start */ + cle_word relsize); /* .rela. size */ + +void * +cle_lookup(struct cle_info *info, + int (*read)(void *, int, off_t), + off_t hdr, /* Offset to start of file. */ + const char *symbol); + +#define CLE_OK 0 +#define CLE_BAD_HEADER 1 +#define CLE_NO_SYMTAB 2 +#define CLE_NO_STRTAB 3 +#define CLE_NO_TEXT 4 +#define CLE_UNDEFINED 5 +#define CLE_UNKNOWN_SEGMENT 6 + +#define CLE_MULTIPLY_DEFINED 20 + +#endif /* CLE_H */ diff --git a/core/loader/elf32.h b/core/loader/elf32.h new file mode 100644 index 000000000..3a68f96cf --- /dev/null +++ b/core/loader/elf32.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)$Id: elf32.h,v 1.1 2006/12/01 15:12:27 bg- Exp $ + */ + +/* @(#)$Id: elf32.h,v 1.1 2006/12/01 15:12:27 bg- Exp $ */ + +#ifndef ELF32_H +#define ELF32_H + +/* + * ELF definitions common to all 32-bit architectures. + */ + +#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 { + unsigned char e_ident[EI_NIDENT]; /* ident bytes */ + elf32_half e_type; /* file type */ + elf32_half e_machine; /* target machine */ + elf32_word e_version; /* file version */ + elf32_addr e_entry; /* start address */ + elf32_off e_phoff; /* phdr file offset */ + elf32_off e_shoff; /* shdr file offset */ + elf32_word e_flags; /* file flags */ + elf32_half e_ehsize; /* sizeof ehdr */ + elf32_half e_phentsize; /* sizeof phdr */ + elf32_half e_phnum; /* number phdrs */ + elf32_half e_shentsize; /* sizeof shdr */ + elf32_half e_shnum; /* number shdrs */ + elf32_half e_shstrndx; /* shdr string index */ +}; + +/* Values for e_type. */ +#define ET_NONE 0 /* Unknown type. */ +#define ET_REL 1 /* Relocatable. */ +#define ET_EXEC 2 /* Executable. */ +#define ET_DYN 3 /* Shared object. */ +#define ET_CORE 4 /* Core file. */ + +struct elf32_shdr { + elf32_word sh_name; /* section name */ + elf32_word sh_type; /* SHT_... */ + elf32_word sh_flags; /* SHF_... */ + elf32_addr sh_addr; /* virtual address */ + elf32_off sh_offset; /* file offset */ + elf32_word sh_size; /* section size */ + elf32_word sh_link; /* misc info */ + elf32_word sh_info; /* misc info */ + elf32_word sh_addralign; /* memory alignment */ + elf32_word sh_entsize; /* entry size if table */ +}; + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +struct elf32_rel { + elf32_addr r_offset; /* Location to be relocated. */ + 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 { + elf32_word st_name; /* String table index of name. */ + elf32_addr st_value; /* Symbol value. */ + elf32_word st_size; /* Size of associated object. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + elf32_half st_shndx; /* Section index of symbol. */ +}; + +#define ELF32_R_SYM(info) ((info) >> 8) +#define ELF32_R_TYPE(info) ((unsigned char)(info)) + +#define ELF_MAGIC_HEADER "\177ELF\001\001\001" +#define ELF_MAGIC_HEADER_SIZE 7 + +#endif /* ELF32_H */