/* * Taken from NetBSD and stripped of the relocations not needed on RTEMS. */ /* $NetBSD: mdreloc.c,v 1.33 2010/01/14 12:12:07 skrll Exp $ */ #include #include #include #include #include #include #include #include #include #include #include "rtl-elf.h" #include "rtl-error.h" #include #include "rtl-unwind.h" /* * Set to 1 to allow untested relocations. If you tested one and it * works or you fixed the relocation please remove the guard. */ #define ALLOW_UNTESTED_RELOCS 1 /* * It is possible for the compiler to emit relocations for unaligned data. * We handle this situation with these inlines. */ #define RELOC_ALIGNED_P(x) \ (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) #define SHT_ARM_EXIDX 0x70000001 /* Section holds ARM unwind info. */ static inline Elf_Addr load_ptr(void *where) { Elf_Addr res; memcpy(&res, where, sizeof(res)); return (res); } static inline void store_ptr(void *where, Elf_Addr val) { memcpy(where, &val, sizeof(val)); } /* * The address of Thumb function symbols is it's real address plus one. * This is done by compiler, thus do not consider symtype here. */ static inline int isThumb(Elf_Word symvalue) { if ((symvalue & 0x1) == 0x1) return true; else return false; } static inline Elf_SOff sign_extend31(Elf_Addr val) { if (0x40000000 & val) val = ~((Elf_Addr)0x7fffffff) | (0x7fffffff & val); return 0x7fffffff & val; } static void* set_veneer(void* tramopline, Elf_Addr target) { /* * http://shell-storm.org/online/Online-Assembler-and-Disassembler/ * * ldr.w pc, [pc] */ uint32_t* tramp = (uint32_t*) tramopline; *tramp++ = 0xf000f8df; *tramp++ = (uint32_t) target; return tramp; } static size_t get_veneer_size(int type) { (void) type; return 8; } size_t rtems_rtl_elf_relocate_tramp_max_size (void) { return 8; } uint32_t rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj, const Elf_Shdr* shdr) { uint32_t flags = 0; if (shdr->sh_type == SHT_ARM_EXIDX) flags = RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_LOAD; return flags; } uint32_t rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj, int section, const char* name, const Elf_Shdr* shdr, const uint32_t flags) { (void) obj; (void) section; (void) name; (void) shdr; return flags; } bool rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj, rtems_rtl_obj_sect* sect) { (void) obj; (void) sect; return false; } bool rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj, rtems_rtl_obj_sect* sect) { (void) obj; (void) sect; return false; } bool rtems_rtl_elf_rel_resolve_sym (Elf_Word type) { return true; } bool rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { (void) obj; (void) rela; (void) sect; (void) symname; (void) syminfo; (void) symvalue; rtems_rtl_set_error (EINVAL, "rela type record not supported"); return false; } bool rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { (void) obj; (void) rela; (void) sect; (void) symname; (void) syminfo; (void) symvalue; rtems_rtl_set_error (EINVAL, "rela type record not supported"); return false; } static bool rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue, const bool parsing) { Elf_Addr *where; Elf_Addr tmp; Elf_Word insn, addend; Elf_Word sign, i1, i2; uint16_t lower_insn, upper_insn; where = (Elf_Addr *)(sect->base + rel->r_offset); switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj)); } break; case R_TYPE(CALL): /* BL/BLX */ case R_TYPE(JUMP24): /* B/BL */ insn = *where; if (insn & 0x00800000) addend = insn | 0xff000000; else addend = insn & 0x00ffffff; if (isThumb(symvalue)) { if ((insn & 0xfe000000) == 0xfa000000); /* Already blx */ else { if ((insn & 0xff000000) == 0xeb000000) { /* BL