Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /*
0002  * Taken from NetBSD and stripped of the relocations not needed on RTEMS.
0003  */
0004 
0005 /*  $NetBSD: mdreloc.c,v 1.33 2010/01/14 12:12:07 skrll Exp $  */
0006 
0007 #include <sys/cdefs.h>
0008 
0009 #include <errno.h>
0010 #include <inttypes.h>
0011 #include <stdio.h>
0012 #include <string.h>
0013 #include <sys/types.h>
0014 #include <sys/stat.h>
0015 
0016 #include <rtems/rtl/rtl.h>
0017 #include "rtl-elf.h"
0018 #include "rtl-error.h"
0019 #include <rtems/rtl/rtl-trace.h>
0020 #include "rtl-unwind-arm.h"
0021 
0022 /*
0023  * Set to 1 to allow untested relocations. If you tested one and it
0024  * works or you fixed the relocation please remove the guard.
0025  */
0026 #define ALLOW_UNTESTED_RELOCS 1
0027 
0028 /*
0029  * It is possible for the compiler to emit relocations for unaligned data.
0030  * We handle this situation with these inlines.
0031  */
0032 #define RELOC_ALIGNED_P(x) \
0033     (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
0034 
0035 #define SHT_ARM_EXIDX  0x70000001 /* Section holds ARM unwind info. */
0036 
0037 static inline Elf_Addr
0038 load_ptr(void *where)
0039 {
0040   Elf_Addr res;
0041 
0042   memcpy(&res, where, sizeof(res));
0043 
0044   return (res);
0045 }
0046 
0047 static inline void
0048 store_ptr(void *where, Elf_Addr val)
0049 {
0050   memcpy(where, &val, sizeof(val));
0051 }
0052 
0053 /*
0054  * The address of Thumb function symbols is it's real address plus one.
0055  * This is done by compiler, thus do not consider symtype here.
0056  */
0057 static inline int
0058 isThumb(Elf_Word symvalue)
0059 {
0060   if ((symvalue & 0x1) == 0x1)
0061     return true;
0062   else return false;
0063 }
0064 
0065 static inline Elf_SOff
0066 sign_extend31(Elf_Addr val)
0067 {
0068   if (0x40000000 & val)
0069     val =  ~((Elf_Addr)0x7fffffff) | (0x7fffffff & val);
0070   return 0x7fffffff & val;
0071 }
0072 
0073 static void*
0074 set_arm_veneer(void* trampoline, Elf_Addr target)
0075 {
0076   /*
0077    *  ARM mode:
0078    *    ldr pc, [pc, #-4]
0079    */
0080   uint32_t* tramp = (uint32_t*) trampoline;
0081 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
0082   *tramp++ = 0xe51ff004;
0083 #else
0084   *tramp++ = 0xe51ff004; /* not tested */
0085 #endif
0086   *tramp++ = (uint32_t) target;
0087   return tramp;
0088 }
0089 
0090 static void*
0091 set_veneer(void* trampoline, Elf_Addr target)
0092 {
0093   /*
0094    * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
0095    *
0096    *  Thumb mode:
0097    *    ldr.w pc, [pc]
0098    *
0099    */
0100 #if defined(__thumb__)
0101   uint32_t* tramp = (uint32_t*) trampoline;
0102  #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
0103   *tramp++ = 0xf000f8df;
0104  #else
0105   *tramp++ = 0xf8dff000; /* not tested */
0106  #endif
0107   *tramp++ = (uint32_t) target;
0108   return tramp;
0109 #else
0110   return set_arm_veneer(trampoline, target);
0111 #endif
0112 }
0113 
0114 static void*
0115 set_thumb_bx_veneer(void* trampoline, Elf_Addr target)
0116 {
0117   /*
0118    * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
0119    *
0120    *  Thumb mode:
0121    *    ldr.w r12, [pc, 4]
0122    *    bx r12
0123    *    .word target
0124    *
0125    */
0126   uint16_t* tramp = (uint16_t*) trampoline;
0127   /* ldr.w r12, [pc, 4]*/
0128   *tramp++ = 0xf8df;
0129   *tramp++ = 0xc002;
0130   /* bx r12 */
0131   *tramp++ = 0x4760;
0132   *tramp++ = (uint16_t) target & 0xffff;
0133   *tramp++ = (uint16_t) ((target >> 16) & 0xffff);
0134   return tramp;
0135 }
0136 
0137 static size_t
0138 get_veneer_size(int type)
0139 {
0140   (void) type;
0141   /* BX veneers need 10 bytes */
0142   return 10;
0143 }
0144 
0145 uint32_t rtems_rtl_obj_tramp_alignment (const rtems_rtl_obj* obj)
0146 {
0147   (void) obj;
0148   return sizeof(uint32_t);
0149 }
0150 
0151 size_t
0152 rtems_rtl_elf_relocate_tramp_max_size (void)
0153 {
0154   return 8;
0155 }
0156 
0157 uint32_t
0158 rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
0159                              const Elf_Shdr*      shdr)
0160 {
0161   uint32_t flags = 0;
0162   if (shdr->sh_type == SHT_ARM_EXIDX)
0163     flags = RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_LOAD;
0164   return flags;
0165 }
0166 
0167 uint32_t
0168 rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
0169                                   int                  section,
0170                                   const char*          name,
0171                                   const Elf_Shdr*      shdr,
0172                                   const uint32_t       flags)
0173 {
0174   (void) obj;
0175   (void) section;
0176   (void) name;
0177   (void) shdr;
0178   return flags;
0179 }
0180 
0181 bool
0182 rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
0183                                   rtems_rtl_obj_sect*  sect)
0184 {
0185   (void) obj;
0186   (void) sect;
0187   return false;
0188 }
0189 
0190 bool
0191 rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
0192                                   rtems_rtl_obj_sect*  sect)
0193 {
0194   (void) obj;
0195   (void) sect;
0196   return false;
0197 }
0198 
0199 bool
0200 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
0201 {
0202   return true;
0203 }
0204 
0205 rtems_rtl_elf_rel_status
0206 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
0207                                    const Elf_Rela*           rela,
0208                                    const rtems_rtl_obj_sect* sect,
0209                                    const char*               symname,
0210                                    const Elf_Byte            syminfo,
0211                                    const Elf_Word            symvalue)
0212 {
0213   (void) obj;
0214   (void) rela;
0215   (void) sect;
0216   (void) symname;
0217   (void) syminfo;
0218   (void) symvalue;
0219   rtems_rtl_set_error (EINVAL, "rela type record not supported");
0220   return rtems_rtl_elf_rel_failure;
0221 }
0222 
0223 rtems_rtl_elf_rel_status
0224 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
0225                              const Elf_Rela*           rela,
0226                              const rtems_rtl_obj_sect* sect,
0227                              const char*               symname,
0228                              const Elf_Byte            syminfo,
0229                              const Elf_Word            symvalue)
0230 {
0231   (void) obj;
0232   (void) rela;
0233   (void) sect;
0234   (void) symname;
0235   (void) syminfo;
0236   (void) symvalue;
0237   rtems_rtl_set_error (EINVAL, "rela type record not supported");
0238   return rtems_rtl_elf_rel_failure;
0239 }
0240 
0241 static rtems_rtl_elf_rel_status
0242 rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
0243                          const Elf_Rel*            rel,
0244                          const rtems_rtl_obj_sect* sect,
0245                          const char*               symname,
0246                          const Elf_Byte            syminfo,
0247                          const Elf_Word            symvalue,
0248                          const bool                parsing)
0249 {
0250   Elf_Addr *where;
0251   Elf_Addr tmp;
0252   Elf_Word insn, addend;
0253   Elf_Word sign, i1, i2;
0254   uint16_t lower_insn, upper_insn;
0255 
0256   where = (Elf_Addr *)(sect->base + rel->r_offset);
0257 
0258   switch (ELF_R_TYPE(rel->r_info)) {
0259     case R_TYPE(NONE):
0260       if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
0261         printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj));
0262       }
0263       break;
0264 
0265     case R_TYPE(CALL):    /* BL/BLX */
0266     case R_TYPE(JUMP24):  /* B/BL<cond> */
0267       if (parsing)
0268       {
0269         addend = 0;
0270       }
0271       else
0272       {
0273         insn = *where;
0274 
0275         if (insn & 0x00800000)
0276           addend = insn | 0xff000000;
0277         else addend = insn & 0x00ffffff;
0278 
0279         if (isThumb(symvalue)) {
0280           if ((insn & 0xfe000000) == 0xfa000000);         /* Already blx */
0281           else {
0282             if ((insn & 0xff000000) == 0xeb000000) {      /* BL <label> */
0283               *where = (insn & 0x00ffffff) | 0xfa000000;  /* BL-->BLX */
0284             } else {
0285               printf("JUMP24 is not suppored from arm to thumb\n");
0286               return rtems_rtl_elf_rel_failure;
0287             }
0288           }
0289         }
0290       }
0291 
0292       if (parsing && sect->base == 0) {
0293         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0294           printf ("rtl: JUMP24/PC24/CALL tramp cache\n");
0295         return rtems_rtl_elf_rel_tramp_cache;
0296       }
0297 
0298       tmp = symvalue + (addend << 2) - (Elf_Addr)where;
0299       tmp = (Elf_Sword)tmp >> 2;
0300 
0301       if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
0302         Elf_Word tramp_addr;
0303         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
0304 
0305         if (parsing) {
0306           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0307             printf ("rtl: JUMP24/PC24/CALL tramp add\n");
0308           return rtems_rtl_elf_rel_tramp_add;
0309         }
0310 
0311         if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0312           rtems_rtl_set_error (EINVAL,
0313                                "%s: CALL/JUMP24: overflow: no tramp memory",
0314                                sect->name);
0315           return rtems_rtl_elf_rel_failure;
0316         }
0317 
0318         tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
0319         obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
0320 
0321         tmp = tramp_addr + (addend << 2) - (Elf_Addr)where;
0322         tmp = (Elf_Sword)tmp >> 2;
0323       }
0324 
0325       if (!parsing) {
0326         *where = (*where & 0xff000000) | (tmp & 0xffffff);
0327 
0328         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0329           printf ("rtl: JUMP24/PC24/CALL %p @ %p in %s\n",
0330                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0331       }
0332       break;
0333 
0334     case R_TYPE(V4BX):
0335       /* Miscellaneous, ignore */
0336       if (!parsing && rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
0337         printf ("rtl: V4BX @ %p in %s\n",
0338                 where, rtems_rtl_obj_oname (obj));
0339       }
0340       break;
0341 
0342     case R_TYPE(MOVT_ABS):
0343     case R_TYPE(MOVW_ABS_NC):
0344       if (!parsing) {
0345         insn = *where;
0346 
0347         addend = ((insn >> 4) & 0xf000) | (insn & 0x0fff);
0348         if (addend & 0x8000)
0349           addend |= 0xffff0000;
0350 
0351         tmp = symvalue + addend;
0352 
0353         if (ELF_R_TYPE(rel->r_info) == R_TYPE(MOVW_ABS_NC))
0354           tmp &= 0xffff;
0355         else {
0356           tmp = (Elf_Sword)tmp >> 16;
0357           if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) {
0358             printf("MOVT_ABS Overflow\n");
0359             return rtems_rtl_elf_rel_failure;
0360           }
0361         }
0362 
0363         *where = (insn & 0xfff0f000) | ((tmp & 0xf000) << 4) | (tmp & 0xfff);
0364 
0365         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0366           printf ("rtl: MOVT_ABS/MOVW_ABS_NC %p @ %p in %s\n",
0367                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0368       }
0369       break;
0370 
0371     case R_TYPE(REL32):     /* word32 (S + A) | T - P */
0372     case R_TYPE(ABS32):     /* word32 (S + A) | T */
0373     case R_TYPE(GLOB_DAT):  /* word32 (S + A) | T */
0374     case R_TYPE(PREL31):    /* word32 (S + A) | T - P */
0375     case R_TYPE(TARGET1):   /* Equivalent to ABS32 */
0376     case R_TYPE(TARGET2):   /* Equivalent to REL32 */
0377       if (!parsing) {
0378         if (__predict_true(RELOC_ALIGNED_P(where))) {
0379           tmp = *where + symvalue;
0380           if (isThumb(symvalue))
0381             tmp |= 1;
0382           if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
0383               ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
0384             tmp -= (Elf_Addr)where;
0385           else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
0386             tmp = sign_extend31(tmp - (Elf_Addr)where);
0387           if (!parsing) {
0388             *where = tmp;
0389           }
0390         } else {
0391           tmp = load_ptr(where) + symvalue;
0392           if (isThumb(symvalue))
0393             tmp |= 1;
0394           if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
0395               ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
0396             tmp -= (Elf_Addr)where;
0397           else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
0398             tmp = sign_extend31(tmp - (Elf_Addr)where);
0399           store_ptr(where, tmp);
0400         }
0401 
0402         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0403           printf ("rtl: REL32/ABS32/GLOB_DAT/PREL31/TARGET2 %p @ %p in %s\n",
0404                   (void *)tmp, where, rtems_rtl_obj_oname (obj));
0405       }
0406       break;
0407 
0408     case R_TYPE(THM_MOVT_ABS):
0409     case R_TYPE(THM_MOVW_ABS_NC):
0410       if (!parsing) {
0411         upper_insn = *(uint16_t *)where;
0412         lower_insn = *((uint16_t *)where + 1);
0413 
0414         addend = ((upper_insn & 0x000f) << 12) | ((upper_insn & 0x0400) << 1) |
0415           ((lower_insn & 0x7000) >> 4) | (lower_insn & 0x00ff);
0416         addend = (addend ^ 0x8000) - 0x8000;
0417 
0418         tmp = addend + symvalue;
0419         if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
0420           tmp >>= 16;
0421 
0422         *(uint16_t *)where = (uint16_t)((upper_insn & 0xfbf0) |
0423                                         ((tmp & 0xf000) >> 12) |
0424                                         ((tmp & 0x0800) >> 1));
0425         *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0x8f00) |
0426                                               ((tmp & 0x0700) << 4) |
0427                                               (tmp & 0x00ff));
0428 
0429         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
0430           printf ("rtl: THM_MOVT_ABS/THM_MOVW_ABS_NC %p @ %p in %s\n",
0431                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0432         }
0433       }
0434       break;
0435 
0436     case R_TYPE(THM_JUMP24):
0437       /* same as THM_PC22; insn b.w */
0438     case R_TYPE(THM_PC22):
0439       if (parsing)
0440       {
0441         addend = 0;
0442         upper_insn = 0;
0443         lower_insn = 0;
0444       }
0445       else
0446       {
0447         upper_insn = *(uint16_t *)where;
0448         lower_insn = *((uint16_t *)where + 1);
0449         sign = (upper_insn & (1 << 10)) >> 10;
0450         i1 = ((lower_insn >> 13) & 1) ^ sign ? 0 : 1;
0451         i2 = ((lower_insn >> 11) & 1) ^ sign ? 0 : 1;
0452         tmp = (i1 << 23) | (i2 << 22) | ((upper_insn & 0x3ff) << 12) | ((lower_insn & 0x7ff) << 1);
0453         addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
0454       }
0455 
0456       if (isThumb(symvalue) == false
0457         && ELF_R_TYPE(rel->r_info) != R_TYPE(THM_JUMP24)) {
0458         /* THM_CALL bl-->blx */
0459         lower_insn &= ~(1<<12);
0460       }
0461 
0462       if (parsing && sect->base == 0) {
0463         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0464           printf ("rtl: THM_CALL/JUMP24 tramp cache\n");
0465         return rtems_rtl_elf_rel_tramp_cache;
0466       }
0467 
0468       tmp = symvalue + addend;
0469       if (isThumb(symvalue)) {
0470         tmp = tmp - (Elf_Addr)where;
0471       } else {
0472         /*
0473          * where[1:0] are set to 0 for ARM-targeted relocations because the jump
0474          * offset[1:0] are also 0
0475          */
0476         tmp = tmp - (Elf_Addr)((uintptr_t)where & 0xfffffffc);
0477       }
0478 
0479       if (isThumb(symvalue) == false && ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
0480         Elf_Word tramp_addr;
0481         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
0482 
0483         if (parsing) {
0484           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0485             printf ("rtl: THM_JUMP24 tramp add: %08x - %p = %i\n",
0486                     symvalue + addend, where, (Elf_Sword) tmp);
0487           return rtems_rtl_elf_rel_tramp_add;
0488         }
0489 
0490         if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0491           rtems_rtl_set_error (EINVAL,
0492                                "%s: THM_JUMP24: overflow: no tramp memory",
0493                                sect->name);
0494           return rtems_rtl_elf_rel_failure;
0495         }
0496 
0497         tramp_addr = (Elf_Addr) obj->tramp_brk;
0498         obj->tramp_brk = set_thumb_bx_veneer(obj->tramp_brk, symvalue);
0499 
0500 
0501         tmp = tramp_addr + addend;
0502         /* This targets a thumb trampoline, so no need to adjust the PC */
0503         tmp = tmp - (Elf_Addr)where;
0504       } else if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
0505         Elf_Word tramp_addr;
0506         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
0507 
0508         if (parsing) {
0509           if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0510             printf ("rtl: THM_CALL/JUMP24 tramp add: %08x - %p = %i\n",
0511                     symvalue + addend, where, (Elf_Sword) tmp);
0512           return rtems_rtl_elf_rel_tramp_add;
0513         }
0514 
0515         if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
0516           rtems_rtl_set_error (EINVAL,
0517                                "%s: THM_CALL/JUMP24: overflow: no tramp memory",
0518                                sect->name);
0519           return rtems_rtl_elf_rel_failure;
0520         }
0521 
0522         tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
0523         tmp = tramp_addr + addend;
0524         if (isThumb(symvalue)) {
0525           obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
0526           tmp = tmp - (Elf_Addr)where;
0527         } else {
0528           /*
0529        * The B[L]X expects ARM code at the target. Align tramp_brk as
0530        * necessary.
0531        */
0532           obj->tramp_brk = (void *)RTEMS_ALIGN_UP((uintptr_t)obj->tramp_brk, 4);
0533       tramp_addr = (Elf_Addr) obj->tramp_brk;
0534           obj->tramp_brk = set_arm_veneer(obj->tramp_brk, symvalue);
0535           /*
0536            * where[1:0] are set to 0 for ARM-targeted relocations because the jump
0537            * offset[1:0] are also 0
0538            */
0539           tmp = tmp - (Elf_Addr)((uintptr_t)where & 0xfffffffc);
0540         }
0541       }
0542 
0543       if (!parsing) {
0544         uint16_t bl_tmp;
0545 
0546         sign = (tmp >> 24) & 1;
0547         *(uint16_t *)where = (uint16_t)((upper_insn & 0xf800) | (sign << 10) |
0548                                         ((tmp >> 12) & 0x3ff));
0549 
0550         bl_tmp = (uint16_t)((lower_insn & 0xd000)|
0551                            ((sign ^ (~(tmp >> 23) & 1)) << 13) |
0552                            ((sign ^ (~(tmp >> 22) & 1)) << 11) |
0553                            ((tmp >> 1) & 0x7ff));
0554         /* Thumb jumps to ARM mode must have 0 in the LSB of the BLX */
0555         if ((bl_tmp & 0xf000) == 0xe000) {
0556           bl_tmp &= 0xfffe;
0557         }
0558         *((uint16_t *)where + 1) = bl_tmp;
0559 
0560         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)){
0561           printf ("rtl: THM_CALL/JUMP24 %p @ %p in %s\n",
0562                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0563         }
0564       }
0565       break;
0566 
0567     case R_TYPE(THM_JUMP19):
0568 
0569       if (!isThumb(symvalue)) {
0570         printf("THM_JUMP19 to arm not supported\n");
0571         return rtems_rtl_elf_rel_failure;
0572       }
0573 
0574       upper_insn = *(uint16_t *)where;
0575       lower_insn = *((uint16_t *)where + 1);
0576       sign = (upper_insn >> 10) & 0x1;
0577 
0578       if ((((upper_insn & 0x3f) >> 7) & 0x7) == 0x7) {
0579         printf("THM_JUMP19 failed\n");
0580         return false; /*if cond <3:1> == '111', see Related codings in armv7a manual */
0581       }
0582 
0583       i1 = (lower_insn >> 13) & 0x1;
0584       i2 = (lower_insn >> 11) & 0x1;
0585 
0586       tmp = ((i2 << 19) | (i1 << 18) | ((upper_insn & 0x3f) << 12) | ((lower_insn & 0x7ff) << 1));
0587       addend = (tmp | ((sign ? 0 : 1) << 20)) - (1 << 20);
0588       tmp = symvalue + addend;
0589 
0590       tmp = tmp - (Elf_Addr)where;
0591 
0592       if (((Elf_Sword)tmp > 0x7ffffe) || ((Elf_Sword)tmp < -0x800000)) {
0593         rtems_rtl_set_error (EINVAL, "%s: Overflow %" PRIu32 " "
0594                              "THM_JUMP19 relocations",
0595                              sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
0596         return rtems_rtl_elf_rel_failure;
0597       }
0598 
0599       sign = (tmp >> 20) & 0x1;
0600       i2 = (tmp >> 19) & 0x1;
0601       i1 = (tmp >> 18) & 0x1;
0602 
0603       *(uint16_t*)where = (upper_insn & 0xfbc0) | (sign << 10) | ((tmp >> 12) & 0x3f);
0604       *((uint16_t*)where + 1) = (lower_insn & 0xd000) | (i1 << 13) |
0605                                 (i2 << 11) | ((tmp >> 1) & 0x7ff);
0606 
0607       if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0608         printf ("rtl: THM_JUMP19 %p @ %p in %s\n",
0609                 (void *)*where, where, rtems_rtl_obj_oname (obj));
0610       break;
0611 
0612     case R_TYPE(TLS_LE32):
0613       if (!parsing) {
0614         addend = *where;
0615         *where = symvalue + addend;
0616         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
0617           printf ("rtl: TLS_LE32 %p @ %p in %s\n",
0618                   (void *)*where, where, rtems_rtl_obj_oname (obj));
0619       }
0620       break;
0621 
0622     case R_TYPE(TLS_GD32):
0623     case R_TYPE(TLS_LDM32):
0624     case R_TYPE(TLS_LDO32):
0625     case R_TYPE(TLS_IE32):
0626     case R_TYPE(TLS_LDO12):
0627     case R_TYPE(TLS_LE12):
0628     case R_TYPE(TLS_IE12GP):
0629       printf("TSL relocations not supported\n");
0630 
0631     default:
0632       printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p",
0633               ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
0634                 (void *)rel->r_offset);
0635       if (!parsing)
0636         printf("contents = %p", (void *)*where);
0637       printf("\n");
0638       rtems_rtl_set_error (EINVAL,
0639                            "%s: Unsupported relocation type %" PRIu32 " "
0640                            "in non-PLT relocations",
0641                            sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
0642       return rtems_rtl_elf_rel_failure;
0643   }
0644 
0645   return rtems_rtl_elf_rel_no_error;
0646 }
0647 
0648 rtems_rtl_elf_rel_status
0649 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
0650                                   const Elf_Rel*            rel,
0651                                   const rtems_rtl_obj_sect* sect,
0652                                   const char*               symname,
0653                                   const Elf_Byte            syminfo,
0654                                   const Elf_Word            symvalue)
0655 {
0656   return rtems_rtl_elf_reloc_rel (obj,
0657                                   rel,
0658                                   sect,
0659                                   symname,
0660                                   syminfo,
0661                                   symvalue,
0662                                   true);
0663 }
0664 
0665 rtems_rtl_elf_rel_status
0666 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
0667                             const Elf_Rel*            rel,
0668                             const rtems_rtl_obj_sect* sect,
0669                             const char*               symname,
0670                             const Elf_Byte            syminfo,
0671                             const Elf_Word            symvalue)
0672 {
0673   return rtems_rtl_elf_reloc_rel (obj,
0674                                   rel,
0675                                   sect,
0676                                   symname,
0677                                   syminfo,
0678                                   symvalue,
0679                                   false);
0680 }