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 #include "contiki.h"
00035
00036 #include "loader/elfloader.h"
00037 #include "loader/elfloader-arch.h"
00038
00039 #include "cfs/cfs.h"
00040 #include "loader/symtab.h"
00041
00042 #include <stddef.h>
00043 #include <string.h>
00044 #include <stdio.h>
00045
00046 #define DEBUG 0
00047 #if DEBUG
00048 #include <stdio.h>
00049 #define PRINTF(...) printf(__VA_ARGS__)
00050 #else
00051 #define PRINTF(...) do {} while (0)
00052 #endif
00053
00054 #define EI_NIDENT 16
00055
00056
00057 struct elf32_ehdr {
00058 unsigned char e_ident[EI_NIDENT];
00059 elf32_half e_type;
00060 elf32_half e_machine;
00061 elf32_word e_version;
00062 elf32_addr e_entry;
00063 elf32_off e_phoff;
00064 elf32_off e_shoff;
00065 elf32_word e_flags;
00066 elf32_half e_ehsize;
00067 elf32_half e_phentsize;
00068 elf32_half e_phnum;
00069 elf32_half e_shentsize;
00070 elf32_half e_shnum;
00071 elf32_half e_shstrndx;
00072 };
00073
00074
00075 #define ET_NONE 0
00076 #define ET_REL 1
00077 #define ET_EXEC 2
00078 #define ET_DYN 3
00079 #define ET_CORE 4
00080
00081 struct elf32_shdr {
00082 elf32_word sh_name;
00083 elf32_word sh_type;
00084 elf32_word sh_flags;
00085 elf32_addr sh_addr;
00086 elf32_off sh_offset;
00087 elf32_word sh_size;
00088 elf32_word sh_link;
00089 elf32_word sh_info;
00090 elf32_word sh_addralign;
00091 elf32_word sh_entsize;
00092 };
00093
00094
00095 #define SHT_NULL 0
00096 #define SHT_PROGBITS 1
00097 #define SHT_SYMTAB 2
00098 #define SHT_STRTAB 3
00099 #define SHT_RELA 4
00100 #define SHT_HASH 5
00101 #define SHT_DYNAMIC 6
00102 #define SHT_NOTE 7
00103 #define SHT_NOBITS 8
00104 #define SHT_REL 9
00105 #define SHT_SHLIB 10
00106 #define SHT_DYNSYM 11
00107 #define SHT_LOPROC 0x70000000
00108 #define SHT_HIPROC 0x7fffffff
00109 #define SHT_LOUSER 0x80000000
00110 #define SHT_HIUSER 0xffffffff
00111
00112 struct elf32_rel {
00113 elf32_addr r_offset;
00114 elf32_word r_info;
00115 };
00116
00117 struct elf32_sym {
00118 elf32_word st_name;
00119 elf32_addr st_value;
00120 elf32_word st_size;
00121 unsigned char st_info;
00122 unsigned char st_other;
00123 elf32_half st_shndx;
00124 };
00125
00126 #define ELF32_R_SYM(info) ((info) >> 8)
00127 #define ELF32_R_TYPE(info) ((unsigned char)(info))
00128
00129 struct relevant_section {
00130 unsigned char number;
00131 unsigned int offset;
00132 char *address;
00133 };
00134
00135 char elfloader_unknown[30];
00136
00137 struct process * const * elfloader_autostart_processes;
00138
00139 static struct relevant_section bss, data, rodata, text;
00140
00141 static const unsigned char elf_magic_header[] =
00142 {0x7f, 0x45, 0x4c, 0x46,
00143 0x01,
00144 0x01,
00145 0x01,
00146 };
00147
00148
00149 static void
00150 seek_read(int fd, unsigned int offset, char *buf, int len)
00151 {
00152 cfs_seek(fd, offset, CFS_SEEK_SET);
00153 cfs_read(fd, buf, len);
00154 #if DEBUG
00155 {
00156 int i;
00157 PRINTF("seek_read: Read len %d from offset %d\n",
00158 len, offset);
00159 for(i = 0; i < len; ++i ) {
00160 PRINTF("%02x ", buf[i]);
00161 }
00162 printf("\n");
00163 }
00164 #endif
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 static void *
00177 find_local_symbol(int fd, const char *symbol,
00178 unsigned int symtab, unsigned short symtabsize,
00179 unsigned int strtab)
00180 {
00181 struct elf32_sym s;
00182 unsigned int a;
00183 char name[30];
00184 struct relevant_section *sect;
00185
00186 for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) {
00187 seek_read(fd, a, (char *)&s, sizeof(s));
00188
00189 if(s.st_name != 0) {
00190 seek_read(fd, strtab + s.st_name, name, sizeof(name));
00191 if(strcmp(name, symbol) == 0) {
00192 if(s.st_shndx == bss.number) {
00193 sect = &bss;
00194 } else if(s.st_shndx == data.number) {
00195 sect = &data;
00196 } else if(s.st_shndx == text.number) {
00197 sect = &text;
00198 } else {
00199 return NULL;
00200 }
00201 return &(sect->address[s.st_value]);
00202 }
00203 }
00204 }
00205 return NULL;
00206 }
00207
00208 static int
00209 relocate_section(int fd,
00210 unsigned int section, unsigned short size,
00211 unsigned int sectionaddr,
00212 char *sectionbase,
00213 unsigned int strs,
00214 unsigned int strtab,
00215 unsigned int symtab, unsigned short symtabsize,
00216 unsigned char using_relas)
00217 {
00218
00219 struct elf32_rela rela;
00220 int rel_size = 0;
00221 struct elf32_sym s;
00222 unsigned int a;
00223 char name[30];
00224 char *addr;
00225 struct relevant_section *sect;
00226
00227
00228 if(using_relas) {
00229 rel_size = sizeof(struct elf32_rela);
00230 } else {
00231 rel_size = sizeof(struct elf32_rel);
00232 }
00233
00234 for(a = section; a < section + size; a += rel_size) {
00235 seek_read(fd, a, (char *)&rela, rel_size);
00236 seek_read(fd,
00237 symtab + sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info),
00238 (char *)&s, sizeof(s));
00239 if(s.st_name != 0) {
00240 seek_read(fd, strtab + s.st_name, name, sizeof(name));
00241 PRINTF("name: %s\n", name);
00242 addr = (char *)symtab_lookup(name);
00243
00244 if(addr == NULL) {
00245 PRINTF("name not found in global: %s\n", name);
00246 addr = find_local_symbol(fd, name, symtab, symtabsize, strtab);
00247 PRINTF("found address %p\n", addr);
00248 }
00249 if(addr == NULL) {
00250 if(s.st_shndx == bss.number) {
00251 sect = &bss;
00252 } else if(s.st_shndx == data.number) {
00253 sect = &data;
00254 } else if(s.st_shndx == rodata.number) {
00255 sect = &rodata;
00256 } else if(s.st_shndx == text.number) {
00257 sect = &text;
00258 } else {
00259 PRINTF("elfloader unknown name: '%30s'\n", name);
00260 memcpy(elfloader_unknown, name, sizeof(elfloader_unknown));
00261 elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0;
00262 return ELFLOADER_SYMBOL_NOT_FOUND;
00263 }
00264 addr = sect->address;
00265 }
00266 } else {
00267 if(s.st_shndx == bss.number) {
00268 sect = &bss;
00269 } else if(s.st_shndx == data.number) {
00270 sect = &data;
00271 } else if(s.st_shndx == rodata.number) {
00272 sect = &rodata;
00273 } else if(s.st_shndx == text.number) {
00274 sect = &text;
00275 } else {
00276 return ELFLOADER_SEGMENT_NOT_FOUND;
00277 }
00278
00279 addr = sect->address;
00280 }
00281
00282 if(!using_relas) {
00283
00284 seek_read(fd, sectionaddr + rela.r_offset, (char *)&rela.r_addend, 4);
00285 }
00286
00287 elfloader_arch_relocate(fd, sectionaddr, sectionbase, &rela, addr);
00288 }
00289 return ELFLOADER_OK;
00290 }
00291
00292 static void *
00293 find_program_processes(int fd,
00294 unsigned int symtab, unsigned short size,
00295 unsigned int strtab)
00296 {
00297 struct elf32_sym s;
00298 unsigned int a;
00299 char name[30];
00300
00301 for(a = symtab; a < symtab + size; a += sizeof(s)) {
00302 seek_read(fd, a, (char *)&s, sizeof(s));
00303
00304 if(s.st_name != 0) {
00305 seek_read(fd, strtab + s.st_name, name, sizeof(name));
00306 if(strcmp(name, "autostart_processes") == 0) {
00307 return &data.address[s.st_value];
00308 }
00309 }
00310 }
00311 return NULL;
00312
00313 }
00314
00315 void
00316 elfloader_init(void)
00317 {
00318 elfloader_autostart_processes = NULL;
00319 }
00320
00321 #if 0
00322 static void
00323 print_chars(unsigned char *ptr, int num)
00324 {
00325 int i;
00326 for(i = 0; i < num; ++i) {
00327 PRINTF("%d", ptr[i]);
00328 if(i == num - 1) {
00329 PRINTF("\n");
00330 } else {
00331 PRINTF(", ");
00332 }
00333 }
00334 }
00335 #endif
00336
00337 int
00338 elfloader_load(int fd)
00339 {
00340 struct elf32_ehdr ehdr;
00341 struct elf32_shdr shdr;
00342 struct elf32_shdr strtable;
00343 unsigned int strs;
00344 unsigned int shdrptr;
00345 unsigned int nameptr;
00346 char name[12];
00347
00348 int i;
00349 unsigned short shdrnum, shdrsize;
00350
00351 unsigned char using_relas = -1;
00352 unsigned short textoff = 0, textsize, textrelaoff = 0, textrelasize;
00353 unsigned short dataoff = 0, datasize, datarelaoff = 0, datarelasize;
00354 unsigned short rodataoff = 0, rodatasize, rodatarelaoff = 0, rodatarelasize;
00355 unsigned short symtaboff = 0, symtabsize;
00356 unsigned short strtaboff = 0, strtabsize;
00357 unsigned short bsssize = 0;
00358
00359 struct process **process;
00360 int ret;
00361
00362 elfloader_unknown[0] = 0;
00363
00364
00365 seek_read(fd, 0, (char *)&ehdr, sizeof(ehdr));
00366
00367
00368
00369
00370 if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
00371 PRINTF("ELF header problems\n");
00372 return ELFLOADER_BAD_ELF_HEADER;
00373 }
00374
00375
00376 shdrptr = ehdr.e_shoff;
00377 seek_read(fd, shdrptr, (char *)&shdr, sizeof(shdr));
00378
00379
00380 shdrsize = ehdr.e_shentsize;
00381 shdrnum = ehdr.e_shnum;
00382
00383 PRINTF("Section header: size %d num %d\n", shdrsize, shdrnum);
00384
00385
00386 seek_read(fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx,
00387 (char *)&strtable, sizeof(strtable));
00388
00389
00390
00391
00392 strs = strtable.sh_offset;
00393
00394 PRINTF("Strtable offset %d\n", strs);
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 textsize = textrelasize = datasize = datarelasize =
00415 rodatasize = rodatarelasize = symtabsize = strtabsize = 0;
00416
00417 bss.number = data.number = rodata.number = text.number = -1;
00418
00419 shdrptr = ehdr.e_shoff;
00420 for(i = 0; i < shdrnum; ++i) {
00421
00422 seek_read(fd, shdrptr, (char *)&shdr, sizeof(shdr));
00423
00424
00425 nameptr = strs + shdr.sh_name;
00426 seek_read(fd, nameptr, name, sizeof(name));
00427 PRINTF("Section shdrptr 0x%x, %d + %d type %d\n",
00428 shdrptr,
00429 strs, shdr.sh_name,
00430 (int)shdr.sh_type);
00431
00432
00433
00434
00435
00436 if(shdr.sh_type == SHT_SYMTAB) {
00437 PRINTF("symtab\n");
00438 symtaboff = shdr.sh_offset;
00439 symtabsize = shdr.sh_size;
00440 } else if(shdr.sh_type == SHT_STRTAB) {
00441 PRINTF("strtab\n");
00442 strtaboff = shdr.sh_offset;
00443 strtabsize = shdr.sh_size;
00444 } else if(strncmp(name, ".text", 5) == 0) {
00445 textoff = shdr.sh_offset;
00446 textsize = shdr.sh_size;
00447 text.number = i;
00448 text.offset = textoff;
00449 } else if(strncmp(name, ".rel.text", 9) == 0) {
00450 using_relas = 0;
00451 textrelaoff = shdr.sh_offset;
00452 textrelasize = shdr.sh_size;
00453 } else if(strncmp(name, ".rela.text", 10) == 0) {
00454 using_relas = 1;
00455 textrelaoff = shdr.sh_offset;
00456 textrelasize = shdr.sh_size;
00457 } else if(strncmp(name, ".data", 5) == 0) {
00458 dataoff = shdr.sh_offset;
00459 datasize = shdr.sh_size;
00460 data.number = i;
00461 data.offset = dataoff;
00462 } else if(strncmp(name, ".rodata", 7) == 0) {
00463
00464 rodataoff = shdr.sh_offset;
00465 rodatasize = shdr.sh_size;
00466 rodata.number = i;
00467 rodata.offset = rodataoff;
00468 } else if(strncmp(name, ".rel.rodata", 11) == 0) {
00469
00470 using_relas = 0;
00471 rodatarelaoff = shdr.sh_offset;
00472 rodatarelasize = shdr.sh_size;
00473 } else if(strncmp(name, ".rela.rodata", 12) == 0) {
00474 using_relas = 1;
00475 rodatarelaoff = shdr.sh_offset;
00476 rodatarelasize = shdr.sh_size;
00477 } else if(strncmp(name, ".rel.data", 9) == 0) {
00478
00479 using_relas = 0;
00480 datarelaoff = shdr.sh_offset;
00481 datarelasize = shdr.sh_size;
00482 } else if(strncmp(name, ".rela.data", 10) == 0) {
00483 using_relas = 1;
00484 datarelaoff = shdr.sh_offset;
00485 datarelasize = shdr.sh_size;
00486 } else if(strncmp(name, ".bss", 4) == 0) {
00487 bsssize = shdr.sh_size;
00488 bss.number = i;
00489 bss.offset = 0;
00490 }
00491
00492
00493 shdrptr += shdrsize;
00494 }
00495
00496 if(symtabsize == 0) {
00497 return ELFLOADER_NO_SYMTAB;
00498 }
00499 if(strtabsize == 0) {
00500 return ELFLOADER_NO_STRTAB;
00501 }
00502 if(textsize == 0) {
00503 return ELFLOADER_NO_TEXT;
00504 }
00505
00506 PRINTF("before allocate ram\n");
00507 bss.address = (char *)elfloader_arch_allocate_ram(bsssize + datasize);
00508 data.address = (char *)bss.address + bsssize;
00509 PRINTF("before allocate rom\n");
00510 text.address = (char *)elfloader_arch_allocate_rom(textsize + rodatasize);
00511 rodata.address = (char *)text.address + textsize;
00512
00513
00514 PRINTF("bss base address: bss.address = 0x%08x\n", bss.address);
00515 PRINTF("data base address: data.address = 0x%08x\n", data.address);
00516 PRINTF("text base address: text.address = 0x%08x\n", text.address);
00517 PRINTF("rodata base address: rodata.address = 0x%08x\n", rodata.address);
00518
00519
00520
00521 PRINTF("elfloader: relocate text\n");
00522 if(textrelasize > 0) {
00523 ret = relocate_section(fd,
00524 textrelaoff, textrelasize,
00525 textoff,
00526 text.address,
00527 strs,
00528 strtaboff,
00529 symtaboff, symtabsize, using_relas);
00530 if(ret != ELFLOADER_OK) {
00531 return ret;
00532 }
00533 }
00534
00535
00536 PRINTF("elfloader: relocate rodata\n");
00537 if(rodatarelasize > 0) {
00538 ret = relocate_section(fd,
00539 rodatarelaoff, rodatarelasize,
00540 rodataoff,
00541 rodata.address,
00542 strs,
00543 strtaboff,
00544 symtaboff, symtabsize, using_relas);
00545 if(ret != ELFLOADER_OK) {
00546 PRINTF("elfloader: data failed\n");
00547 return ret;
00548 }
00549 }
00550
00551
00552 PRINTF("elfloader: relocate data\n");
00553 if(datarelasize > 0) {
00554 ret = relocate_section(fd,
00555 datarelaoff, datarelasize,
00556 dataoff,
00557 data.address,
00558 strs,
00559 strtaboff,
00560 symtaboff, symtabsize, using_relas);
00561 if(ret != ELFLOADER_OK) {
00562 PRINTF("elfloader: data failed\n");
00563 return ret;
00564 }
00565 }
00566
00567
00568 elfloader_arch_write_rom(fd, textoff, textsize, text.address);
00569 elfloader_arch_write_rom(fd, rodataoff, rodatasize, rodata.address);
00570
00571 memset(bss.address, 0, bsssize);
00572 seek_read(fd, dataoff, data.address, datasize);
00573
00574 PRINTF("elfloader: autostart search\n");
00575 process = (struct process **) find_local_symbol(fd, "autostart_processes", symtaboff, symtabsize, strtaboff);
00576 if(process != NULL) {
00577 PRINTF("elfloader: autostart found\n");
00578 elfloader_autostart_processes = process;
00579 return ELFLOADER_OK;
00580 } else {
00581 PRINTF("elfloader: no autostart\n");
00582 process = (struct process **) find_program_processes(fd, symtaboff, symtabsize, strtaboff);
00583 if(process != NULL) {
00584 PRINTF("elfloader: FOUND PRG\n");
00585 }
00586 return ELFLOADER_NO_STARTPOINT;
00587 }
00588 }
00589