00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <stdio.h>
00037 #include <string.h>
00038
00039 #include "contiki.h"
00040
00041 #include "loader/elf32.h"
00042 #include "loader/cle.h"
00043 #include "loader/sym.h"
00044
00045 #define NDEBUG
00046 #include "lib/assert.h"
00047
00048 #ifdef NDEBUG
00049 #define PRINTF(...) do {} while (0)
00050 #else
00051 #define PRINTF(...) printf(__VA_ARGS__)
00052 #endif
00053
00054 #define NOLL 0
00055
00056 #ifdef __AVR__
00057
00058
00059
00060
00061 #ifndef __GNUC__
00062 #eror "You lose!!!"
00063 #endif
00064 #endif
00065
00066
00067
00068
00069
00070 int
00071 cle_read_info(struct cle_info *info,
00072 int (*pread)(void *, int, off_t),
00073 off_t hdr)
00074 {
00075
00076
00077
00078
00079
00080 union {
00081 struct elf32_ehdr ehdr;
00082 struct elf32_shdr shdr;
00083 } huge;
00084 #define ehdr huge.ehdr
00085 #define shdr huge.shdr
00086
00087 off_t shoff;
00088 cle_off strs;
00089 cle_half shnum;
00090 cle_half shentsize;
00091 cle_word strtabsize = 0;
00092 int i, ret;
00093
00094 memset(info, 0x0, sizeof(*info));
00095
00096 ret = pread(&ehdr, sizeof(ehdr), hdr);
00097 assert(ret > 0);
00098
00099
00100 if(memcmp(ehdr.e_ident, ELF_MAGIC_HEADER, ELF_MAGIC_HEADER_SIZE) != 0) {
00101 return CLE_BAD_HEADER;
00102 }
00103
00104 shoff = hdr + ehdr.e_shoff;
00105 shentsize = ehdr.e_shentsize;
00106 shnum = ehdr.e_shnum;
00107
00108
00109 ret = pread(&shdr, sizeof(shdr), shoff + shentsize*ehdr.e_shstrndx);
00110 assert(ret > 0);
00111
00112
00113
00114
00115
00116
00117
00118
00119 strs = shdr.sh_offset;
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 for(i = 0; i < shnum; ++i) {
00136 ret = pread(&shdr, sizeof(shdr), shoff);
00137 assert(ret > 0);
00138
00139
00140 ret = pread(info->name, sizeof(info->name), hdr + strs + shdr.sh_name);
00141 assert(ret > 0);
00142
00143 if(strncmp(info->name, ".text", 5) == 0) {
00144 info->textoff = shdr.sh_offset;
00145 info->textsize = shdr.sh_size;
00146 info->text_shndx = i;
00147 } else if(strncmp(info->name, ".rela.text", 10) == 0) {
00148 info->textrelaoff = shdr.sh_offset;
00149 info->textrelasize = shdr.sh_size;
00150 } else if(strncmp(info->name, ".data", 5) == 0) {
00151 info->dataoff = shdr.sh_offset;
00152 info->datasize = shdr.sh_size;
00153 info->data_shndx = i;
00154 } else if(strncmp(info->name, ".rela.data", 10) == 0) {
00155 info->datarelaoff = shdr.sh_offset;
00156 info->datarelasize = shdr.sh_size;
00157 } else if(strncmp(info->name, ".symtab", 7) == 0) {
00158 info->symtaboff = shdr.sh_offset;
00159 info->symtabsize = shdr.sh_size;
00160 } else if(strncmp(info->name, ".strtab", 7) == 0) {
00161 info->strtaboff = shdr.sh_offset;
00162 strtabsize = shdr.sh_size;
00163 } else if(strncmp(info->name, ".bss", 4) == 0) {
00164 info->bsssize = shdr.sh_size;
00165 info->bss_shndx = i;
00166 } else {
00167 info->name[sizeof(info->name) - 1] = 0;
00168 PRINTF("cle: unknown section %.12s\n", info->name);
00169 }
00170
00171
00172 shoff += shentsize;
00173 }
00174
00175 if(info->symtabsize == 0) {
00176 return CLE_NO_SYMTAB;
00177 }
00178 if(strtabsize == 0) {
00179 return CLE_NO_STRTAB;
00180 }
00181 if(info->textsize == 0) {
00182 return CLE_NO_TEXT;
00183 }
00184
00185 return CLE_OK;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 int
00197 cle_relocate(struct cle_info *info,
00198 int (*pread)(void *, int, off_t),
00199 off_t hdr,
00200 void *segmem,
00201 cle_off reloff,
00202 cle_word relsize)
00203 {
00204 struct elf32_rela rela;
00205 struct elf32_sym s;
00206 off_t off;
00207 cle_addr addr;
00208 int ret;
00209
00210 for(off = hdr + reloff;
00211 off < hdr + reloff + relsize;
00212 off += sizeof(struct elf32_rela)) {
00213 ret = pread(&rela, sizeof(rela), off);
00214 assert(ret > 0);
00215 ret = pread(&s, sizeof(s),
00216 hdr + info->symtaboff
00217 + sizeof(struct elf32_sym)*ELF32_R_SYM(rela.r_info));
00218 assert(ret > 0);
00219
00220 if(s.st_shndx == info->bss_shndx) {
00221 addr = (cle_addr)(uintptr_t)info->bss;
00222 } else if(s.st_shndx == info->data_shndx) {
00223 addr = (cle_addr)(uintptr_t)info->data;
00224 } else if(s.st_shndx == info->text_shndx) {
00225 addr = info->text;
00226 } else {
00227 addr = NOLL;
00228 }
00229
00230 if(s.st_name == 0) {
00231 if(addr == NOLL) {
00232 return CLE_UNKNOWN_SEGMENT;
00233 }
00234 } else {
00235 ret = pread(info->name, sizeof(info->name),
00236 hdr + info->strtaboff + s.st_name);
00237 assert(ret > 0);
00238 cle_addr sym = (cle_addr)(uintptr_t)sym_function(info->name);
00239 #ifdef __AVR__
00240 if(sym != NOLL)
00241 sym = sym << 1;
00242 #endif
00243 if(sym == NOLL)
00244 sym = (cle_addr)(uintptr_t)sym_object(info->name);
00245
00246 if(addr == NOLL && sym != NOLL) {
00247 addr = sym;
00248 } else if(addr != NOLL && sym == NOLL) {
00249 addr = addr + s.st_value;
00250 } else if(addr == NOLL && sym == NOLL) {
00251 PRINTF("cle: undefined reference to %.32s (%d)\n",
00252 info->name, s.st_info);
00253 return CLE_UNDEFINED;
00254 } else if(addr != NOLL && sym != NOLL) {
00255 PRINTF("cle: multiple definitions of %.32s (%d)\n",
00256 info->name, s.st_info);
00257 return CLE_MULTIPLY_DEFINED;
00258 }
00259 }
00260
00261 addr += rela.r_addend;
00262
00263 ret = cle_write_reloc(segmem + rela.r_offset, &rela, addr, info);
00264 if(ret != CLE_OK) {
00265 return ret;
00266 }
00267 }
00268 return CLE_OK;
00269 }
00270
00271
00272
00273
00274
00275
00276 void *
00277 cle_lookup(struct cle_info *info,
00278 int (*pread)(void *, int, off_t),
00279 off_t hdr,
00280 const char *symbol)
00281
00282 {
00283 struct elf32_sym s;
00284 off_t a;
00285 cle_addr addr;
00286 int ret;
00287
00288 for(a = hdr + info->symtaboff;
00289 a < hdr + info->symtaboff + info->symtabsize;
00290 a += sizeof(s)) {
00291 ret = pread(&s, sizeof(s), a);
00292 assert(ret > 0);
00293
00294 if(s.st_name != 0) {
00295 ret = pread(info->name, sizeof(info->name),
00296 hdr + info->strtaboff + s.st_name);
00297 assert(ret > 0);
00298
00299 if(strcmp(info->name, symbol) == 0) {
00300 if(s.st_shndx == info->bss_shndx) {
00301 addr = (cle_addr)(uintptr_t)info->bss;
00302 } else if(s.st_shndx == info->data_shndx) {
00303 addr = (cle_addr)(uintptr_t)info->data;
00304 } else if(s.st_shndx == info->text_shndx) {
00305 addr = info->text;
00306 #ifdef __AVR__
00307 return (void *)(uintptr_t)((addr + s.st_value) >> 1);
00308 #endif
00309 } else {
00310 return NULL;
00311 }
00312
00313 return (void *)(uintptr_t)(addr + s.st_value);
00314 }
00315 }
00316 }
00317 return NULL;
00318 }