Contiki 2.6
|
00001 #include <stdlib.h> 00002 #include <malloc.h> 00003 #include <loader/elfloader-arch-otf.h> 00004 00005 #if 0 00006 #include <stdio.h> 00007 #define PRINTF(...) printf(__VA_ARGS__) 00008 #else 00009 #define PRINTF(...) do {} while (0) 00010 #endif 00011 00012 #define ELF32_R_TYPE(info) ((unsigned char)(info)) 00013 00014 /* Supported relocations */ 00015 00016 #define R_ARM_ABS32 2 00017 #define R_ARM_THM_CALL 10 00018 00019 /* Adapted from elfloader-avr.c */ 00020 00021 int 00022 elfloader_arch_relocate(int input_fd, 00023 struct elfloader_output *output, 00024 unsigned int sectionoffset, 00025 char *sectionaddr, 00026 struct elf32_rela *rela, char *addr) 00027 { 00028 unsigned int type; 00029 00030 type = ELF32_R_TYPE(rela->r_info); 00031 00032 cfs_seek(input_fd, sectionoffset + rela->r_offset, CFS_SEEK_SET); 00033 00034 /* PRINTF("elfloader_arch_relocate: type %d\n", type); */ 00035 /* PRINTF("Addr: %p, Addend: %ld\n", addr, rela->r_addend); */ 00036 switch(type) { 00037 case R_ARM_ABS32: 00038 { 00039 int32_t addend; 00040 cfs_read(input_fd, (char*)&addend, 4); 00041 addr += addend; 00042 elfloader_output_write_segment(output,(char*) &addr, 4); 00043 PRINTF("%p: addr: %p\n", sectionaddr +rela->r_offset, 00044 addr); 00045 } 00046 break; 00047 case R_ARM_THM_CALL: 00048 { 00049 uint16_t instr[2]; 00050 int32_t offset; 00051 char *base; 00052 cfs_read(input_fd, (char*)instr, 4); 00053 /* Ignore the addend since it will be zero for calls to symbols, 00054 and I can't think of a case when doing a relative call to 00055 a non-symbol position */ 00056 base = sectionaddr + (rela->r_offset + 4); 00057 00058 if (((instr[1]) & 0xe800) == 0xe800) { 00059 /* BL or BLX */ 00060 if (((uint32_t)addr) & 0x1) { 00061 /* BL */ 00062 instr[1] |= 0x1800; 00063 } else { 00064 #if defined(__ARM_ARCH_4T__) 00065 return ELFLOADER_UNHANDLED_RELOC; 00066 #else 00067 /* BLX */ 00068 instr[1] &= ~0x1800; 00069 instr[1] |= 0x0800; 00070 #endif 00071 } 00072 } 00073 /* Adjust address for BLX */ 00074 if ((instr[1] & 0x1800) == 0x0800) { 00075 addr = (char*)((((uint32_t)addr) & 0xfffffffd) 00076 | (((uint32_t)base) & 0x00000002)); 00077 } 00078 offset = addr - (sectionaddr + (rela->r_offset + 4)); 00079 if (offset < -(1<<22) || offset >= (1<<22)) { 00080 PRINTF("elfloader-arm.c: offset %d too large for relative call\n", 00081 (int)offset); 00082 } 00083 /* PRINTF("%p: %04x %04x offset: %d addr: %p\n", sectionaddr +rela->r_offset, instr[0], instr[1], (int)offset, addr); */ 00084 instr[0] = (instr[0] & 0xf800) | ((offset>>12)&0x07ff); 00085 instr[1] = (instr[1] & 0xf800) | ((offset>>1)&0x07ff); 00086 elfloader_output_write_segment(output, (char*)instr, 4); 00087 /* PRINTF("cfs_write: %04x %04x\n",instr[0], instr[1]); */ 00088 } 00089 break; 00090 00091 default: 00092 PRINTF("elfloader-arm.c: unsupported relocation type %d\n", type); 00093 return ELFLOADER_UNHANDLED_RELOC; 00094 } 00095 return ELFLOADER_OK; 00096 }