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 #include "contiki.h"
00036
00037 #include "loader/elfloader-otf.h"
00038 #include "loader/elfloader-arch-otf.h"
00039
00040 #include "cfs/cfs.h"
00041 #include "loader/symtab.h"
00042
00043 #include <stddef.h>
00044 #include <string.h>
00045 #include <stdio.h>
00046
00047 #if 0
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 **elfloader_autostart_processes;
00138
00139 static struct relevant_section bss, data, rodata, text;
00140
00141 const static unsigned char elf_magic_header[] =
00142 {0x7f, 0x45, 0x4c, 0x46,
00143 0x01,
00144 0x01,
00145 0x01,
00146 };
00147
00148
00149 static int
00150 copy_segment_data(int input_fd, unsigned int offset,
00151 struct elfloader_output *output, unsigned int len)
00152 {
00153 char buffer[16];
00154 int res;
00155 if (cfs_seek(input_fd, offset, CFS_SEEK_SET) != offset) return ELFLOADER_INPUT_ERROR;
00156 while(len > sizeof(buffer)) {
00157 res = cfs_read(input_fd, buffer, sizeof(buffer));
00158 if (res != sizeof(buffer)) return ELFLOADER_INPUT_ERROR;
00159 res = elfloader_output_write_segment(output, buffer, sizeof(buffer));
00160 if (res != sizeof(buffer)) return ELFLOADER_OUTPUT_ERROR;
00161 len -= sizeof(buffer);
00162 }
00163 res = cfs_read(input_fd, buffer, len);
00164 if (res != len) return ELFLOADER_INPUT_ERROR;
00165 res = elfloader_output_write_segment(output, buffer, len);
00166 if (res != len) return ELFLOADER_OUTPUT_ERROR;
00167 return ELFLOADER_OK;
00168 }
00169
00170 static int
00171 seek_read(int fd, unsigned int offset, char *buf, int len)
00172 {
00173 if (cfs_seek(fd, offset, CFS_SEEK_SET) != offset) return -1;
00174 return cfs_read(fd, buf, len);
00175 }
00176
00177 static void *
00178 find_local_symbol(int input_fd, const char *symbol,
00179 unsigned int symtab, unsigned short symtabsize,
00180 unsigned int strtab)
00181 {
00182 struct elf32_sym s;
00183 unsigned int a;
00184 char name[30];
00185 struct relevant_section *sect;
00186 int ret;
00187
00188 for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) {
00189 ret = seek_read(input_fd, a, (char *)&s, sizeof(s));
00190 if (ret < 0) return NULL;
00191
00192 if(s.st_name != 0) {
00193 ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name));
00194 if (ret < 0) return NULL;
00195
00196 if(strcmp(name, symbol) == 0) {
00197 if(s.st_shndx == bss.number) {
00198 sect = &bss;
00199 } else if(s.st_shndx == data.number) {
00200 sect = &data;
00201 } else if(s.st_shndx == text.number) {
00202 sect = &text;
00203 } else {
00204 return NULL;
00205 }
00206 return &(sect->address[s.st_value]);
00207 }
00208 }
00209 }
00210 return NULL;
00211 }
00212
00213 static int
00214 relocate_section(int input_fd,
00215 struct elfloader_output *output,
00216 unsigned int section, unsigned short size,
00217 unsigned int sectionaddr,
00218 char *sectionbase,
00219 unsigned int strs,
00220 unsigned int strtab,
00221 unsigned int symtab, unsigned short symtabsize,
00222 unsigned char using_relas)
00223 {
00224
00225 struct elf32_rela rela;
00226 int rel_size = 0;
00227 struct elf32_sym s;
00228 unsigned int a;
00229 char name[30];
00230 char *addr;
00231 struct relevant_section *sect;
00232 int ret;
00233
00234
00235 if(using_relas) {
00236 rel_size = sizeof(struct elf32_rela);
00237 } else {
00238 rel_size = sizeof(struct elf32_rel);
00239 }
00240
00241 for(a = section; a < section + size; a += rel_size) {
00242 ret = seek_read(input_fd, a, (char *)&rela, rel_size);
00243 if (ret < 0) return ELFLOADER_INPUT_ERROR;
00244 ret = seek_read(input_fd,
00245 (symtab +
00246 sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info)),
00247 (char *)&s, sizeof(s));
00248 if (ret < 0) return ELFLOADER_INPUT_ERROR;
00249 if(s.st_name != 0) {
00250 ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name));
00251 if (ret < 0) return ELFLOADER_INPUT_ERROR;
00252 PRINTF("name: %s\n", name);
00253 addr = (char *)symtab_lookup(name);
00254
00255 if(addr == NULL) {
00256 PRINTF("name not found in global: %s\n", name);
00257 addr = find_local_symbol(input_fd, name, symtab, symtabsize, strtab);
00258 PRINTF("found address %p\n", addr);
00259 }
00260 if(addr == NULL) {
00261 if(s.st_shndx == bss.number) {
00262 sect = &bss;
00263 } else if(s.st_shndx == data.number) {
00264 sect = &data;
00265 } else if(s.st_shndx == rodata.number) {
00266 sect = &rodata;
00267 } else if(s.st_shndx == text.number) {
00268 sect = &text;
00269 } else {
00270 PRINTF("elfloader unknown name: '%30s'\n", name);
00271 memcpy(elfloader_unknown, name, sizeof(elfloader_unknown));
00272 elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0;
00273 return ELFLOADER_SYMBOL_NOT_FOUND;
00274 }
00275 addr = sect->address;
00276 }
00277 } else {
00278 if(s.st_shndx == bss.number) {
00279 sect = &bss;
00280 } else if(s.st_shndx == data.number) {
00281 sect = &data;
00282 } else if(s.st_shndx == rodata.number) {
00283 sect = &rodata;
00284 } else if(s.st_shndx == text.number) {
00285 sect = &text;
00286 } else {
00287 return ELFLOADER_SEGMENT_NOT_FOUND;
00288 }
00289
00290 addr = sect->address;
00291 }
00292
00293 #if 0
00294
00295 if (!using_relas) {
00296
00297 ret = seek_read(fd, sectionaddr + rela.r_offset, &rela.r_addend, 4);
00298 if (ret < 0) return ELFLOADER_INPUT_ERROR;
00299 }
00300 #endif
00301 {
00302
00303 unsigned int offset = elfloader_output_segment_offset(output);
00304 if (rela.r_offset < offset) {
00305 PRINTF("elfloader relocation out of offset order\n");
00306
00307 }
00308 if (rela.r_offset > offset) {
00309 ret = copy_segment_data(input_fd, offset+sectionaddr, output,
00310 rela.r_offset - offset);
00311 if (ret != ELFLOADER_OK) return ret;
00312 }
00313 }
00314 ret = elfloader_arch_relocate(input_fd, output, sectionaddr, sectionbase,
00315 &rela, addr);
00316 if (ret != ELFLOADER_OK) return ret;
00317 }
00318 return ELFLOADER_OK;
00319 }
00320
00321 static void *
00322 find_program_processes(int input_fd,
00323 unsigned int symtab, unsigned short size,
00324 unsigned int strtab)
00325 {
00326 struct elf32_sym s;
00327 unsigned int a;
00328 char name[30];
00329
00330 for(a = symtab; a < symtab + size; a += sizeof(s)) {
00331 seek_read(input_fd, a, (char *)&s, sizeof(s));
00332
00333 if(s.st_name != 0) {
00334 seek_read(input_fd, strtab + s.st_name, name, sizeof(name));
00335 if(strcmp(name, "autostart_processes") == 0) {
00336 return &data.address[s.st_value];
00337 }
00338 }
00339 }
00340 return NULL;
00341
00342 }
00343
00344 void
00345 elfloader_init(void)
00346 {
00347 elfloader_autostart_processes = NULL;
00348 }
00349
00350 #if 0
00351 static void
00352 print_chars(unsigned char *ptr, int num)
00353 {
00354 int i;
00355 for(i = 0; i < num; ++i) {
00356 PRINTF("%d", ptr[i]);
00357 if(i == num - 1) {
00358 PRINTF("\n");
00359 } else {
00360 PRINTF(", ");
00361 }
00362 }
00363 }
00364 #endif
00365
00366 static int
00367 copy_segment(int input_fd,
00368 struct elfloader_output *output,
00369 unsigned int section, unsigned short size,
00370 unsigned int sectionaddr,
00371 char *sectionbase,
00372 unsigned int strs,
00373 unsigned int strtab,
00374 unsigned int symtab, unsigned short symtabsize,
00375 unsigned char using_relas,
00376 unsigned int seg_size, unsigned int seg_type)
00377 {
00378 unsigned int offset;
00379 int ret;
00380 ret = elfloader_output_start_segment(output, seg_type,sectionbase, seg_size);
00381 if (ret != ELFLOADER_OK) return ret;
00382 ret = relocate_section(input_fd, output,
00383 section, size,
00384 sectionaddr,
00385 sectionbase,
00386 strs,
00387 strtab,
00388 symtab, symtabsize, using_relas);
00389 if (ret != ELFLOADER_OK) return ret;
00390 offset = elfloader_output_segment_offset(output);
00391 ret = copy_segment_data(input_fd, offset+sectionaddr, output,seg_size - offset);
00392 if (ret != ELFLOADER_OK) return ret;
00393 return elfloader_output_end_segment(output);
00394 }
00395
00396
00397 int
00398 elfloader_load(int input_fd, struct elfloader_output *output)
00399 {
00400 struct elf32_ehdr ehdr;
00401 struct elf32_shdr shdr;
00402 struct elf32_shdr strtable;
00403 unsigned int strs;
00404 unsigned int shdrptr;
00405 unsigned int nameptr;
00406 char name[12];
00407
00408 int i;
00409 unsigned short shdrnum, shdrsize;
00410
00411 unsigned char using_relas = -1;
00412 unsigned short textoff = 0, textsize, textrelaoff = 0, textrelasize;
00413 unsigned short dataoff = 0, datasize, datarelaoff = 0, datarelasize;
00414 unsigned short rodataoff = 0, rodatasize, rodatarelaoff = 0, rodatarelasize;
00415 unsigned short symtaboff = 0, symtabsize;
00416 unsigned short strtaboff = 0, strtabsize;
00417 unsigned short bsssize = 0;
00418
00419 struct process **process;
00420 int ret;
00421
00422 elfloader_unknown[0] = 0;
00423
00424
00425 ret = seek_read(input_fd, 0, (char *)&ehdr, sizeof(ehdr));
00426 if (ret != sizeof(ehdr)) return ELFLOADER_INPUT_ERROR;
00427
00428
00429
00430
00431 if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
00432 PRINTF("ELF header problems\n");
00433 return ELFLOADER_BAD_ELF_HEADER;
00434 }
00435
00436
00437 shdrptr = ehdr.e_shoff;
00438 ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr));
00439 if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR;
00440
00441
00442 shdrsize = ehdr.e_shentsize;
00443 shdrnum = ehdr.e_shnum;
00444
00445
00446 ret = seek_read(input_fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx,
00447 (char *)&strtable, sizeof(strtable));
00448 if (ret != sizeof(strtable)) return ELFLOADER_INPUT_ERROR;
00449
00450
00451
00452
00453 strs = strtable.sh_offset;
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 textsize = textrelasize = datasize = datarelasize =
00474 rodatasize = rodatarelasize = symtabsize = strtabsize = 0;
00475
00476 bss.number = data.number = rodata.number = text.number = -1;
00477
00478 shdrptr = ehdr.e_shoff;
00479 for(i = 0; i < shdrnum; ++i) {
00480
00481 ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr));
00482 if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR;
00483
00484
00485 nameptr = strs + shdr.sh_name;
00486 ret = seek_read(input_fd, nameptr, name, sizeof(name));
00487 if (ret != sizeof(name)) return ELFLOADER_INPUT_ERROR;
00488
00489
00490
00491
00492
00493
00494 if(strncmp(name, ".text", 5) == 0) {
00495 textoff = shdr.sh_offset;
00496 textsize = shdr.sh_size;
00497 text.number = i;
00498 text.offset = textoff;
00499 } else if(strncmp(name, ".rel.text", 9) == 0) {
00500 using_relas = 0;
00501 textrelaoff = shdr.sh_offset;
00502 textrelasize = shdr.sh_size;
00503 } else if(strncmp(name, ".rela.text", 10) == 0) {
00504 using_relas = 1;
00505 textrelaoff = shdr.sh_offset;
00506 textrelasize = shdr.sh_size;
00507 } else if(strncmp(name, ".data", 5) == 0) {
00508 dataoff = shdr.sh_offset;
00509 datasize = shdr.sh_size;
00510 data.number = i;
00511 data.offset = dataoff;
00512 } else if(strncmp(name, ".rodata", 7) == 0) {
00513
00514 rodataoff = shdr.sh_offset;
00515 rodatasize = shdr.sh_size;
00516 rodata.number = i;
00517 rodata.offset = rodataoff;
00518 } else if(strncmp(name, ".rel.rodata", 11) == 0) {
00519
00520 using_relas = 0;
00521 rodatarelaoff = shdr.sh_offset;
00522 rodatarelasize = shdr.sh_size;
00523 } else if(strncmp(name, ".rela.rodata", 12) == 0) {
00524 using_relas = 1;
00525 rodatarelaoff = shdr.sh_offset;
00526 rodatarelasize = shdr.sh_size;
00527 } else if(strncmp(name, ".rel.data", 9) == 0) {
00528
00529 using_relas = 0;
00530 datarelaoff = shdr.sh_offset;
00531 datarelasize = shdr.sh_size;
00532 } else if(strncmp(name, ".rela.data", 10) == 0) {
00533 using_relas = 1;
00534 datarelaoff = shdr.sh_offset;
00535 datarelasize = shdr.sh_size;
00536 } else if(strncmp(name, ".symtab", 7) == 0) {
00537 symtaboff = shdr.sh_offset;
00538 symtabsize = shdr.sh_size;
00539 } else if(strncmp(name, ".strtab", 7) == 0) {
00540 strtaboff = shdr.sh_offset;
00541 strtabsize = shdr.sh_size;
00542 } else if(strncmp(name, ".bss", 4) == 0) {
00543 bsssize = shdr.sh_size;
00544 bss.number = i;
00545 bss.offset = 0;
00546 }
00547
00548
00549 shdrptr += shdrsize;
00550 }
00551
00552 if(symtabsize == 0) {
00553 return ELFLOADER_NO_SYMTAB;
00554 }
00555 if(strtabsize == 0) {
00556 return ELFLOADER_NO_STRTAB;
00557 }
00558 if(textsize == 0) {
00559 return ELFLOADER_NO_TEXT;
00560 }
00561
00562
00563 if (bsssize) {
00564 bss.address = (char *)
00565 elfloader_output_alloc_segment(output, ELFLOADER_SEG_BSS, bsssize);
00566 if (!bss.address) return ELFLOADER_OUTPUT_ERROR;
00567 }
00568 if (datasize) {
00569 data.address = (char *)
00570 elfloader_output_alloc_segment(output,ELFLOADER_SEG_DATA,datasize);
00571 if (!data.address) return ELFLOADER_OUTPUT_ERROR;
00572 }
00573 if (textsize) {
00574 text.address = (char *)
00575 elfloader_output_alloc_segment(output,ELFLOADER_SEG_TEXT,textsize);
00576 if (!text.address) return ELFLOADER_OUTPUT_ERROR;
00577 }
00578 if (rodatasize) {
00579 rodata.address = (char *)
00580 elfloader_output_alloc_segment(output,ELFLOADER_SEG_RODATA,rodatasize);
00581 if (!rodata.address) return ELFLOADER_OUTPUT_ERROR;
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591 PRINTF("elfloader: relocate text\n");
00592 if(textrelasize > 0) {
00593 ret = copy_segment(input_fd, output,
00594 textrelaoff, textrelasize,
00595 textoff,
00596 text.address,
00597 strs,
00598 strtaboff,
00599 symtaboff, symtabsize, using_relas,
00600 textsize, ELFLOADER_SEG_TEXT);
00601 if(ret != ELFLOADER_OK) {
00602 return ret;
00603 }
00604 }
00605
00606
00607 PRINTF("elfloader: relocate rodata\n");
00608 if(rodatarelasize > 0) {
00609 ret = copy_segment(input_fd, output,
00610 rodatarelaoff, rodatarelasize,
00611 rodataoff,
00612 rodata.address,
00613 strs,
00614 strtaboff,
00615 symtaboff, symtabsize, using_relas,
00616 rodatasize, ELFLOADER_SEG_RODATA);
00617 if(ret != ELFLOADER_OK) {
00618 PRINTF("elfloader: data failed\n");
00619 return ret;
00620 }
00621 }
00622
00623
00624 PRINTF("elfloader: relocate data\n");
00625 if(datarelasize > 0) {
00626 ret = copy_segment(input_fd, output,
00627 datarelaoff, datarelasize,
00628 dataoff,
00629 data.address,
00630 strs,
00631 strtaboff,
00632 symtaboff, symtabsize, using_relas,
00633 datasize, ELFLOADER_SEG_DATA);
00634 if(ret != ELFLOADER_OK) {
00635 PRINTF("elfloader: data failed\n");
00636 return ret;
00637 }
00638 ret = elfloader_output_end_segment(output);
00639 if (ret != ELFLOADER_OK) return ret;
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649 {
00650
00651 unsigned int len = bsssize;
00652 static const char zeros[16] = {0};
00653 ret = elfloader_output_start_segment(output, ELFLOADER_SEG_BSS,
00654 bss.address,bsssize);
00655 if (ret != ELFLOADER_OK) return ret;
00656 while(len > sizeof(zeros)) {
00657 ret = elfloader_output_write_segment(output, zeros, sizeof(zeros));
00658 if (ret != sizeof(zeros)) return ELFLOADER_OUTPUT_ERROR;
00659 len -= sizeof(zeros);
00660 }
00661 ret = elfloader_output_write_segment(output, zeros, len);
00662 if (ret != len) return ELFLOADER_OUTPUT_ERROR;
00663 }
00664
00665 PRINTF("elfloader: autostart search\n");
00666 process = find_local_symbol(input_fd, "autostart_processes", symtaboff, symtabsize, strtaboff);
00667 if(process != NULL) {
00668 PRINTF("elfloader: autostart found\n");
00669 elfloader_autostart_processes = process;
00670 return ELFLOADER_OK;
00671 } else {
00672 PRINTF("elfloader: no autostart\n");
00673 process = find_program_processes(input_fd, symtaboff, symtabsize, strtaboff);
00674 if(process != NULL) {
00675 PRINTF("elfloader: FOUND PRG\n");
00676 }
00677 return ELFLOADER_NO_STARTPOINT;
00678 }
00679 }
00680