source: rtems/cpukit/libdl/rtl-mdreloc-arm.c @ 7219d3c

Last change on this file since 7219d3c was 5500232, checked in by Ryan Long <ryan.long@…>, on 08/08/22 at 14:23:48

libdl: Refactor shared code in ARM and AArch64

rtl-mdreloc-arm.c was used as the basis for rtl-mdreloc-aarch64.c. This lead
to some code being shared by the two files. The code was consolidated into
rtl-unwind-arm.c.

Closes #4686

  • Property mode set to 100644
File size: 18.2 KB
Line 
1/*
2 * Taken from NetBSD and stripped of the relocations not needed on RTEMS.
3 */
4
5/*  $NetBSD: mdreloc.c,v 1.33 2010/01/14 12:12:07 skrll Exp $  */
6
7#include <sys/cdefs.h>
8
9#include <errno.h>
10#include <inttypes.h>
11#include <stdio.h>
12#include <string.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15
16#include <rtems/rtl/rtl.h>
17#include "rtl-elf.h"
18#include "rtl-error.h"
19#include <rtems/rtl/rtl-trace.h>
20#include "rtl-unwind-arm.h"
21
22/*
23 * Set to 1 to allow untested relocations. If you tested one and it
24 * works or you fixed the relocation please remove the guard.
25 */
26#define ALLOW_UNTESTED_RELOCS 1
27
28/*
29 * It is possible for the compiler to emit relocations for unaligned data.
30 * We handle this situation with these inlines.
31 */
32#define RELOC_ALIGNED_P(x) \
33        (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
34
35#define SHT_ARM_EXIDX  0x70000001 /* Section holds ARM unwind info. */
36
37static inline Elf_Addr
38load_ptr(void *where)
39{
40  Elf_Addr res;
41
42  memcpy(&res, where, sizeof(res));
43
44  return (res);
45}
46
47static inline void
48store_ptr(void *where, Elf_Addr val)
49{
50  memcpy(where, &val, sizeof(val));
51}
52
53/*
54 * The address of Thumb function symbols is it's real address plus one.
55 * This is done by compiler, thus do not consider symtype here.
56 */
57static inline int
58isThumb(Elf_Word symvalue)
59{
60  if ((symvalue & 0x1) == 0x1)
61    return true;
62  else return false;
63}
64
65static inline Elf_SOff
66sign_extend31(Elf_Addr val)
67{
68  if (0x40000000 & val)
69    val =  ~((Elf_Addr)0x7fffffff) | (0x7fffffff & val);
70  return 0x7fffffff & val;
71}
72
73static void*
74set_veneer(void* tramopline, Elf_Addr target)
75{
76  /*
77   * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
78   *
79   *  Thumb mode:
80   *    ldr.w pc, [pc]
81   *
82   *  ARM mode:
83   *    ldr pc, [pc, #-4]
84   *
85   */
86  uint32_t* tramp = (uint32_t*) tramopline;
87#if defined(__thumb__)
88 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
89  *tramp++ = 0xf000f8df;
90 #else
91  *tramp++ = 0xf8dff000; /* not tested */
92 #endif
93#else
94 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
95  *tramp++ = 0xe51ff004;
96 #else
97  *tramp++ = 0xe51ff004; /* not tested */
98 #endif
99#endif
100  *tramp++ = (uint32_t) target;
101  return tramp;
102}
103
104static size_t
105get_veneer_size(int type)
106{
107  (void) type;
108  return 8;
109}
110
111size_t
112rtems_rtl_elf_relocate_tramp_max_size (void)
113{
114  return 8;
115}
116
117uint32_t
118rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
119                             const Elf_Shdr*      shdr)
120{
121  uint32_t flags = 0;
122  if (shdr->sh_type == SHT_ARM_EXIDX)
123    flags = RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_LOAD;
124  return flags;
125}
126
127uint32_t
128rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
129                                  int                  section,
130                                  const char*          name,
131                                  const Elf_Shdr*      shdr,
132                                  const uint32_t       flags)
133{
134  (void) obj;
135  (void) section;
136  (void) name;
137  (void) shdr;
138  return flags;
139}
140
141bool
142rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
143                                  rtems_rtl_obj_sect*  sect)
144{
145  (void) obj;
146  (void) sect;
147  return false;
148}
149
150bool
151rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
152                                  rtems_rtl_obj_sect*  sect)
153{
154  (void) obj;
155  (void) sect;
156  return false;
157}
158
159bool
160rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
161{
162  return true;
163}
164
165rtems_rtl_elf_rel_status
166rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
167                                   const Elf_Rela*           rela,
168                                   const rtems_rtl_obj_sect* sect,
169                                   const char*               symname,
170                                   const Elf_Byte            syminfo,
171                                   const Elf_Word            symvalue)
172{
173  (void) obj;
174  (void) rela;
175  (void) sect;
176  (void) symname;
177  (void) syminfo;
178  (void) symvalue;
179  rtems_rtl_set_error (EINVAL, "rela type record not supported");
180  return rtems_rtl_elf_rel_failure;
181}
182
183rtems_rtl_elf_rel_status
184rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
185                             const Elf_Rela*           rela,
186                             const rtems_rtl_obj_sect* sect,
187                             const char*               symname,
188                             const Elf_Byte            syminfo,
189                             const Elf_Word            symvalue)
190{
191  (void) obj;
192  (void) rela;
193  (void) sect;
194  (void) symname;
195  (void) syminfo;
196  (void) symvalue;
197  rtems_rtl_set_error (EINVAL, "rela type record not supported");
198  return rtems_rtl_elf_rel_failure;
199}
200
201static rtems_rtl_elf_rel_status
202rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
203                         const Elf_Rel*            rel,
204                         const rtems_rtl_obj_sect* sect,
205                         const char*               symname,
206                         const Elf_Byte            syminfo,
207                         const Elf_Word            symvalue,
208                         const bool                parsing)
209{
210  Elf_Addr *where;
211  Elf_Addr tmp;
212  Elf_Word insn, addend;
213  Elf_Word sign, i1, i2;
214  uint16_t lower_insn, upper_insn;
215
216  where = (Elf_Addr *)(sect->base + rel->r_offset);
217
218  switch (ELF_R_TYPE(rel->r_info)) {
219    case R_TYPE(NONE):
220      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
221        printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj));
222      }
223      break;
224
225    case R_TYPE(CALL):    /* BL/BLX */
226    case R_TYPE(JUMP24):  /* B/BL<cond> */
227      if (parsing)
228      {
229        addend = 0;
230      }
231      else
232      {
233        insn = *where;
234
235        if (insn & 0x00800000)
236          addend = insn | 0xff000000;
237        else addend = insn & 0x00ffffff;
238
239        if (isThumb(symvalue)) {
240          if ((insn & 0xfe000000) == 0xfa000000);         /* Already blx */
241          else {
242            if ((insn & 0xff000000) == 0xeb000000) {      /* BL <label> */
243              *where = (insn & 0x00ffffff) | 0xfa000000;  /* BL-->BLX */
244            } else {
245              printf("JUMP24 is not suppored from arm to thumb\n");
246              return rtems_rtl_elf_rel_failure;
247            }
248          }
249        }
250      }
251
252      if (parsing && sect->base == 0) {
253        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
254          printf ("rtl: JUMP24/PC24/CALL tramp cache\n");
255        return rtems_rtl_elf_rel_tramp_cache;
256      }
257
258      tmp = symvalue + (addend << 2) - (Elf_Addr)where;
259      tmp = (Elf_Sword)tmp >> 2;
260
261      if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
262        Elf_Word tramp_addr;
263        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
264
265        if (parsing) {
266          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
267            printf ("rtl: JUMP24/PC24/CALL tramp add\n");
268          return rtems_rtl_elf_rel_tramp_add;
269        }
270
271        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
272          rtems_rtl_set_error (EINVAL,
273                               "%s: CALL/JUMP24: overflow: no tramp memory",
274                               sect->name);
275          return rtems_rtl_elf_rel_failure;
276        }
277
278        tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
279        obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
280
281        tmp = tramp_addr + (addend << 2) - (Elf_Addr)where;
282        tmp = (Elf_Sword)tmp >> 2;
283      }
284
285      if (!parsing) {
286        *where = (*where & 0xff000000) | (tmp & 0xffffff);
287
288        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
289          printf ("rtl: JUMP24/PC24/CALL %p @ %p in %s\n",
290                  (void *)*where, where, rtems_rtl_obj_oname (obj));
291      }
292      break;
293
294    case R_TYPE(V4BX):
295      /* Miscellaneous, ignore */
296      if (!parsing && rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
297        printf ("rtl: V4BX @ %p in %s\n",
298                where, rtems_rtl_obj_oname (obj));
299      }
300      break;
301
302    case R_TYPE(MOVT_ABS):
303    case R_TYPE(MOVW_ABS_NC):
304      if (!parsing) {
305        insn = *where;
306
307        addend = ((insn >> 4) & 0xf000) | (insn & 0x0fff);
308        if (addend & 0x8000)
309          addend |= 0xffff0000;
310
311        tmp = symvalue + addend;
312
313        if (ELF_R_TYPE(rel->r_info) == R_TYPE(MOVW_ABS_NC))
314          tmp &= 0xffff;
315        else {
316          tmp = (Elf_Sword)tmp >> 16;
317          if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) {
318            printf("MOVT_ABS Overflow\n");
319            return rtems_rtl_elf_rel_failure;
320          }
321        }
322
323        *where = (insn & 0xfff0f000) | ((tmp & 0xf000) << 4) | (tmp & 0xfff);
324
325        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
326          printf ("rtl: MOVT_ABS/MOVW_ABS_NC %p @ %p in %s\n",
327                  (void *)*where, where, rtems_rtl_obj_oname (obj));
328      }
329      break;
330
331    case R_TYPE(REL32):     /* word32 (S + A) | T - P */
332    case R_TYPE(ABS32):     /* word32 (S + A) | T */
333    case R_TYPE(GLOB_DAT):  /* word32 (S + A) | T */
334    case R_TYPE(PREL31):    /* word32 (S + A) | T - P */
335    case R_TYPE(TARGET1):   /* Equivalent to ABS32 */
336    case R_TYPE(TARGET2):   /* Equivalent to REL32 */
337      if (!parsing) {
338        if (__predict_true(RELOC_ALIGNED_P(where))) {
339          tmp = *where + symvalue;
340          if (isThumb(symvalue))
341            tmp |= 1;
342          if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
343              ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
344            tmp -= (Elf_Addr)where;
345          else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
346            tmp = sign_extend31(tmp - (Elf_Addr)where);
347          if (!parsing) {
348            *where = tmp;
349          }
350        } else {
351          tmp = load_ptr(where) + symvalue;
352          if (isThumb(symvalue))
353            tmp |= 1;
354          if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
355              ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
356            tmp -= (Elf_Addr)where;
357          else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
358            tmp = sign_extend31(tmp - (Elf_Addr)where);
359          store_ptr(where, tmp);
360        }
361
362        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
363          printf ("rtl: REL32/ABS32/GLOB_DAT/PREL31/TARGET2 %p @ %p in %s\n",
364                  (void *)tmp, where, rtems_rtl_obj_oname (obj));
365      }
366      break;
367
368    case R_TYPE(THM_MOVT_ABS):
369    case R_TYPE(THM_MOVW_ABS_NC):
370      if (!parsing) {
371        upper_insn = *(uint16_t *)where;
372        lower_insn = *((uint16_t *)where + 1);
373
374        addend = ((upper_insn & 0x000f) << 12) | ((upper_insn & 0x0400) << 1) |
375          ((lower_insn & 0x7000) >> 4) | (lower_insn & 0x00ff);
376        addend = (addend ^ 0x8000) - 0x8000;
377
378        tmp = addend + symvalue;
379        if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
380          tmp >>= 16;
381
382        *(uint16_t *)where = (uint16_t)((upper_insn & 0xfbf0) |
383                                        ((tmp & 0xf000) >> 12) |
384                                        ((tmp & 0x0800) >> 1));
385        *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0x8f00) |
386                                              ((tmp & 0x0700) << 4) |
387                                              (tmp & 0x00ff));
388
389        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
390          printf ("rtl: THM_MOVT_ABS/THM_MOVW_ABS_NC %p @ %p in %s\n",
391                  (void *)*where, where, rtems_rtl_obj_oname (obj));
392        }
393      }
394      break;
395
396    case R_TYPE(THM_JUMP24):
397      /* same as THM_PC22; insn b.w */
398    case R_TYPE(THM_PC22):
399      if (parsing)
400      {
401        addend = 0;
402        upper_insn = 0;
403        lower_insn = 0;
404      }
405      else
406      {
407        upper_insn = *(uint16_t *)where;
408        lower_insn = *((uint16_t *)where + 1);
409        sign = (upper_insn & (1 << 10)) >> 10;
410        i1 = ((lower_insn >> 13) & 1) ^ sign ? 0 : 1;
411        i2 = ((lower_insn >> 11) & 1) ^ sign ? 0 : 1;
412        tmp = (i1 << 23) | (i2 << 22) | ((upper_insn & 0x3ff) << 12) | ((lower_insn & 0x7ff) << 1);
413        addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
414      }
415
416      if (isThumb(symvalue)) ;/*Thumb to Thumb call, nothing to care */
417      else {
418        if (ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
419          tmp = (tmp + 2) & ~3; /* aligned to 4 bytes only for JUMP24 */
420#if !ALLOW_UNTESTED_RELOCS
421          printf("THM_JUMP24 to arm not supported\n");
422          return rtems_rtl_elf_rel_failure;
423#endif
424        }
425        else {
426          /* THM_CALL bl-->blx */
427          lower_insn &= ~(1<<12);
428        }
429      }
430
431      if (parsing && sect->base == 0) {
432        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
433          printf ("rtl: THM_CALL/JUMP24 tramp cache\n");
434        return rtems_rtl_elf_rel_tramp_cache;
435      }
436
437      tmp = symvalue + addend;
438      tmp = tmp - (Elf_Addr)where;
439
440      if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
441        Elf_Word tramp_addr;
442        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
443
444        if (parsing) {
445          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
446            printf ("rtl: THM_CALL/JUMP24 tramp add: %08x - %p = %i\n",
447                    symvalue + addend, where, (Elf_Sword) tmp);
448          return rtems_rtl_elf_rel_tramp_add;
449        }
450
451        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
452          rtems_rtl_set_error (EINVAL,
453                               "%s: THM_CALL/JUMP24: overflow: no tramp memory",
454                               sect->name);
455          return rtems_rtl_elf_rel_failure;
456        }
457
458        tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
459        obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
460
461
462        tmp = tramp_addr + addend;
463        tmp = tmp - (Elf_Addr)where;
464      }
465
466      if (!parsing) {
467        sign = (tmp >> 24) & 1;
468        *(uint16_t *)where = (uint16_t)((upper_insn & 0xf800) | (sign << 10) |
469                                        ((tmp >> 12) & 0x3ff));
470
471        *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0xd000)|
472                                              ((sign ^ (~(tmp >> 23) & 1)) << 13) |
473                                              ((sign ^ (~(tmp >> 22) & 1)) << 11) |
474                                              ((tmp >> 1) & 0x7ff));
475
476        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)){
477          printf ("rtl: THM_CALL/JUMP24 %p @ %p in %s\n",
478                  (void *)*where, where, rtems_rtl_obj_oname (obj));
479        }
480      }
481      break;
482
483    case R_TYPE(THM_JUMP19):
484
485      if (!isThumb(symvalue)) {
486        printf("THM_JUMP19 to arm not supported\n");
487        return rtems_rtl_elf_rel_failure;
488      }
489
490      upper_insn = *(uint16_t *)where;
491      lower_insn = *((uint16_t *)where + 1);
492      sign = (upper_insn >> 10) & 0x1;
493
494      if ((((upper_insn & 0x3f) >> 7) & 0x7) == 0x7) {
495        printf("THM_JUMP19 failed\n");
496        return false; /*if cond <3:1> == '111', see Related codings in armv7a manual */
497      }
498
499      i1 = (lower_insn >> 13) & 0x1;
500      i2 = (lower_insn >> 11) & 0x1;
501
502      tmp = ((i2 << 19) | (i1 << 18) | ((upper_insn & 0x3f) << 12) | ((lower_insn & 0x7ff) << 1));
503      addend = (tmp | ((sign ? 0 : 1) << 20)) - (1 << 20);
504      tmp = symvalue + addend;
505
506      tmp = tmp - (Elf_Addr)where;
507
508      if (((Elf_Sword)tmp > 0x7ffffe) || ((Elf_Sword)tmp < -0x800000)) {
509        rtems_rtl_set_error (EINVAL, "%s: Overflow %" PRIu32 " "
510                             "THM_JUMP19 relocations",
511                             sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
512        return rtems_rtl_elf_rel_failure;
513      }
514
515      sign = (tmp >> 20) & 0x1;
516      i2 = (tmp >> 19) & 0x1;
517      i1 = (tmp >> 18) & 0x1;
518
519      *(uint16_t*)where = (upper_insn & 0xfbc0) | (sign << 10) | ((tmp >> 12) & 0x3f);
520      *((uint16_t*)where + 1) = (lower_insn & 0xd000) | (i1 << 13) |
521                                (i2 << 11) | ((tmp >> 1) & 0x7ff);
522
523      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
524        printf ("rtl: THM_JUMP19 %p @ %p in %s\n",
525                (void *)*where, where, rtems_rtl_obj_oname (obj));
526      break;
527
528    case R_TYPE(TLS_LE32):
529#if ALLOW_UNTESTED_RELOCS
530      if (!parsing) {
531        addend = *where;
532        *where = symvalue + addend;
533        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
534          printf ("rtl: TLS_LE32 %p @ %p in %s\n",
535                  (void *)*where, where, rtems_rtl_obj_oname (obj));
536      }
537      break;
538#endif
539    case R_TYPE(TLS_GD32):
540    case R_TYPE(TLS_LDM32):
541    case R_TYPE(TLS_LDO32):
542    case R_TYPE(TLS_IE32):
543    case R_TYPE(TLS_LDO12):
544    case R_TYPE(TLS_LE12):
545    case R_TYPE(TLS_IE12GP):
546      printf("TSL relocations not supported\n");
547
548    default:
549      printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p",
550              ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
551                (void *)rel->r_offset);
552      if (!parsing)
553        printf("contents = %p", (void *)*where);
554      printf("\n");
555      rtems_rtl_set_error (EINVAL,
556                           "%s: Unsupported relocation type %" PRIu32 " "
557                           "in non-PLT relocations",
558                           sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
559      return rtems_rtl_elf_rel_failure;
560  }
561
562  return rtems_rtl_elf_rel_no_error;
563}
564
565rtems_rtl_elf_rel_status
566rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
567                                  const Elf_Rel*            rel,
568                                  const rtems_rtl_obj_sect* sect,
569                                  const char*               symname,
570                                  const Elf_Byte            syminfo,
571                                  const Elf_Word            symvalue)
572{
573  return rtems_rtl_elf_reloc_rel (obj,
574                                  rel,
575                                  sect,
576                                  symname,
577                                  syminfo,
578                                  symvalue,
579                                  true);
580}
581
582rtems_rtl_elf_rel_status
583rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
584                            const Elf_Rel*            rel,
585                            const rtems_rtl_obj_sect* sect,
586                            const char*               symname,
587                            const Elf_Byte            syminfo,
588                            const Elf_Word            symvalue)
589{
590  return rtems_rtl_elf_reloc_rel (obj,
591                                  rel,
592                                  sect,
593                                  symname,
594                                  syminfo,
595                                  symvalue,
596                                  false);
597}
Note: See TracBrowser for help on using the repository browser.