source: rtems/cpukit/libdl/rtl-mdreloc-aarch64.c @ 0bd6514a

Last change on this file since 0bd6514a was 0bd6514a, checked in by Ryan Long <ryan.long@…>, on 07/19/22 at 17:20:31

cpukit/libdl: Add support for AArch64

rtl-mdreloc-aarch64.c and elf_machdep.h came from NetBSD.

Updates #4682

  • Property mode set to 100644
File size: 18.7 KB
Line 
1/*
2 * Taken from NetBSD and stripped of the relocations not needed on RTEMS.
3 */
4
5/* $NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg Exp $ */
6
7/*-
8 * Copyright (c) 2014 The NetBSD Foundation, Inc.
9 * All rights reserved.
10 *
11 * This code is derived from software contributed to The NetBSD Foundation
12 * by Matt Thomas of 3am Software Foundry.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/*-
37 * Copyright (c) 2014-2015 The FreeBSD Foundation
38 * All rights reserved.
39 *
40 * Portions of this software were developed by Andrew Turner
41 * under sponsorship from the FreeBSD Foundation.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 *    notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 *    notice, this list of conditions and the following disclaimer in the
50 *    documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65#include <sys/cdefs.h>
66#ifndef lint
67__RCSID("$NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg Exp $");
68#endif /* not lint */
69
70#include <sys/types.h>
71#include <string.h>
72#include <errno.h>
73#include <inttypes.h>
74#include <sys/stat.h>
75#include <sys/endian.h>
76#include <unwind.h>
77
78#include <rtems/rtl/rtl.h>
79#include "rtl-elf.h"
80#include "rtl-error.h"
81#include <rtems/rtl/rtl-trace.h>
82#include "rtl-unwind.h"
83
84typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
85typedef _Unwind_Word _uw;
86
87struct tls_data {
88  size_t    td_tlsindex;
89  Elf_Addr  td_tlsoffs;
90};
91
92rtems_rtl_elf_rel_status
93rtems_rtl_elf_reloc_rela (
94  rtems_rtl_obj*            obj,
95  const Elf_Rela*           rela,
96  const rtems_rtl_obj_sect* sect,
97  const char*               symname,
98  const Elf_Byte            syminfo,
99  const Elf_Word            symvalue,
100  const bool                parsing
101);
102
103#define __BITS(hi,lo) ((~((~(Elf_Addr)0)<<((hi)+1)))&((~(Elf_Addr)0)<<(lo)))
104#define WIDTHMASK(w) (0xffffffffffffffffUL >> (64 - (w)))
105
106static inline bool
107checkoverflow(Elf_Addr addr, int bitwidth, Elf_Addr targetaddr,
108    const char *bitscale, void *where, Elf64_Addr off)
109{
110  const Elf_Addr mask = ~__BITS(bitwidth - 1, 0);
111
112  if (((addr & mask) != 0) && ((addr & mask) != mask)) {
113    printf("kobj_reloc: Relocation 0x%jx too far from %p"
114        " (base+0x%jx) for %dbit%s\n",
115        (uintptr_t)targetaddr, where, off, bitwidth, bitscale);
116    return true;
117  }
118
119  return false;
120}
121
122static inline bool
123checkalign(Elf_Addr addr, int alignbyte, void *where, Elf64_Addr off)
124{
125  if ((addr & (alignbyte - 1)) != 0) {
126    printf("kobj_reloc: Relocation 0x%jx unaligned at %p"
127        " (base+0x%jx). must be aligned %d\n",
128        (uintptr_t)addr, where, off, alignbyte);
129    return true;
130  }
131  return false;
132}
133
134/*
135 * Set to 1 to allow untested relocations. If you tested one and it
136 * works or you fixed the relocation please remove the guard.
137 */
138#define ALLOW_UNTESTED_RELOCS 1
139
140static void*
141set_veneer(void* tramopline, Elf_Addr target)
142{
143  /*
144   * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
145   *
146   * ldr x9, #8
147   * br x9
148   *
149   */
150  uint64_t* tramp = (uint64_t*) tramopline;
151#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
152  *tramp++ = 0xd61f012058000049;
153#else
154  *tramp++ = 0xd61f012058000049; /* not tested */
155#endif
156  *tramp++ = (uint64_t) target;
157  return tramp;
158}
159
160static size_t
161get_veneer_size(int type)
162{
163  (void) type;
164  return 16;
165}
166
167size_t
168rtems_rtl_elf_relocate_tramp_max_size (void)
169{
170  return 16;
171}
172
173uint32_t
174rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
175                             const Elf_Shdr*      shdr)
176{
177  return 0;
178}
179
180uint32_t
181rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
182                                  int                  section,
183                                  const char*          name,
184                                  const Elf_Shdr*      shdr,
185                                  const uint32_t       flags)
186{
187  (void) obj;
188  (void) section;
189  (void) name;
190  (void) shdr;
191  return flags;
192}
193
194bool
195rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
196                                  rtems_rtl_obj_sect*  sect)
197{
198  (void) obj;
199  (void) sect;
200  return false;
201}
202
203bool
204rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
205                                 rtems_rtl_obj_sect*  sect)
206{
207  (void) obj;
208  (void) sect;
209  return false;
210}
211
212bool
213rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
214{
215  return true;
216}
217
218rtems_rtl_elf_rel_status
219rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
220                          const Elf_Rela*           rela,
221                          const rtems_rtl_obj_sect* sect,
222                          const char*               symname,
223                          const Elf_Byte            syminfo,
224                          const Elf_Word            symvalue,
225                          const bool                parsing)
226{
227  Elf64_Addr *where;
228  Elf32_Addr *where32;
229  Elf_Addr    off = rela->r_offset;
230  Elf_Addr    target;
231  Elf_Addr    raddr;
232  uint32_t   *insn, immhi, immlo, shift;
233
234  where = (Elf_Addr *)(sect->base + rela->r_offset);
235  where32 = (void *)where;
236
237  insn = (uint32_t *)where;
238
239  /*
240   * S - the address of the symbol
241   * A - the addend of the reolcation
242   * P - the address of the place being relocated (derived from r_offset)
243   * Page(expr) - the page address of the expression expr, defined as (expr & ~0xFFF).
244   */
245  switch (ELF_R_TYPE(rela->r_info)) {
246    case R_TYPE(NONE):
247      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
248        printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj));
249      }
250      break;
251
252    case R_TYPE(ABS64): /* word S + A */
253    case R_TYPE(GLOB_DAT): /* word S + A */
254      if (!parsing) {
255        target = (Elf_Addr)symvalue + rela->r_addend;
256
257        if (*where != target)
258          *where = target;
259
260        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
261          printf ("rtl: reloc 64/GLOB_DAT in %s --> %p in %s\n",
262                  sect->name, (void *)*where,
263                  rtems_rtl_obj_oname (obj));
264      }
265      break;
266
267    /*
268     * If S is a normal symbol, resolves to the difference between the static
269     * link address of S and the execution address of S. If S is the null symbol
270     * (ELF symbol index 0), resolves to the difference between the static link
271     * address of P and the execution address of P.
272     */
273    case R_TYPE(RELATIVE):  /* Delta(S) + A */
274      if (!parsing) {
275        *where = (Elf_Addr)(sect->base + rela->r_addend);
276        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
277          printf ("rtl: reloc RELATIVE in %s --> %p in %s\n",
278                  sect->name, (void *)*where,
279                  rtems_rtl_obj_oname (obj));
280      }
281      break;
282
283    case R_TYPE(COPY):
284      /*
285       * These are deferred until all other relocations have
286       * been done.  All we do here is make sure that the
287       * COPY relocation is not in a shared library.  They
288       * are allowed only in executable files.
289       */
290      printf("rtl: reloc COPY (please report)\n");
291      break;
292
293    case R_AARCH64_ADD_ABS_LO12_NC: /* S + A */
294    case R_AARCH64_LDST8_ABS_LO12_NC:
295    case R_AARCH_LDST16_ABS_LO12_NC:
296    case R_AARCH_LDST32_ABS_LO12_NC:
297    case R_AARCH_LDST64_ABS_LO12_NC:
298      switch (ELF_R_TYPE(rela->r_info)) {
299        case R_AARCH64_ADD_ABS_LO12_NC:
300        case R_AARCH64_LDST8_ABS_LO12_NC:
301          shift = 0;
302          break;
303        case R_AARCH_LDST16_ABS_LO12_NC:
304          shift = 1;
305          break;
306        case R_AARCH_LDST32_ABS_LO12_NC:
307          shift = 2;
308          break;
309        case R_AARCH_LDST64_ABS_LO12_NC:
310          shift = 3;
311          break;
312        default:
313          printf("illegal rtype: %ld\n", ELF_R_TYPE(rela->r_info));
314          break;
315      }
316
317      /*
318       * S + A
319       *  e.g.) add  x0,x0,#:lo12:<sym>+<addend>
320       *        ldrb w0,[x0,#:lo12:<sym>+<addend>]
321       *        ldrh w0,[x0,#:lo12:<sym>+<addend>]
322       *        ldr  w0,[x0,#:lo12:<sym>+<addend>]
323       *        ldr  x0,[x0,#:lo12:<sym>+<addend>]
324       */
325      if (!parsing) {
326        target = (Elf_Addr)symvalue + rela->r_addend;
327        if (checkalign(target, 1 << shift, where, off)) {
328          printf ("rtl: reloc checkalign failed in %s --> %p in %s\n",
329                  sect->name, (void *)*where,
330                  rtems_rtl_obj_oname (obj));
331          printf("ELF_R_TYPE is : %ld\n", ELF_R_TYPE(rela->r_info));
332          break;
333        }
334        target &= WIDTHMASK(12);
335        target >>= shift;
336        *insn = htole32(
337            (le32toh(*insn) & ~__BITS(21,10)) | (target << 10));
338      }
339      break;
340
341    case R_AARCH64_ADR_PREL_PG_HI21:
342      /*
343       * Page(S + A) - Page(P)
344       *  e.g.) adrp x0,<sym>+<addend>
345       */
346      if (!parsing) {
347        target = (Elf_Addr)symvalue + rela->r_addend;
348        target = target >> 12;
349        raddr = target << 12;
350        target -= (uintptr_t)where >> 12;
351
352        if (checkoverflow(target, 21, raddr, " x 4k", where, off)) {
353          return rtems_rtl_elf_rel_failure;
354        }
355
356        immlo = target & WIDTHMASK(2);
357        immhi = (target >> 2) & WIDTHMASK(19);
358        *insn = htole32((le32toh(*insn) &
359            ~(__BITS(30,29) | __BITS(23,5))) |
360            (immlo << 29) | (immhi << 5));
361      }
362      break;
363
364    case R_AARCH_JUMP26:
365    case R_AARCH_CALL26:
366      /*
367       * S + A - P
368       *  e.g.) b <sym>+<addend>
369       *        bl <sym>+<addend>
370       */
371      if (parsing && sect->base == 0) {
372        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
373          printf ("rtl: JUMP26/PC26/CALL tramp cache\n");
374        return rtems_rtl_elf_rel_tramp_cache;
375      }
376
377      raddr = (Elf_Addr)symvalue + rela->r_addend;
378      target = raddr - (uintptr_t)where;
379      if (checkalign(target, 4, where, off)) {
380        return rtems_rtl_elf_rel_failure;
381      }
382
383      target = (intptr_t)target >> 2;
384
385      if (((Elf_Sword)target > 0x1FFFFFF) || ((Elf_Sword)target < -0x2000000)) {
386        Elf_Word tramp_addr;
387        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
388
389        if (parsing) {
390          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
391            printf ("rtl: JUMP26/PC26/CALL tramp add\n");
392          return rtems_rtl_elf_rel_tramp_add;
393        }
394
395        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
396          rtems_rtl_set_error (EINVAL,
397                               "%s: CALL/JUMP26: overflow: no tramp memory",
398                               sect->name);
399          return rtems_rtl_elf_rel_failure;
400        }
401
402        tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
403        obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
404
405        target = tramp_addr + rela->r_addend - (uintptr_t)where;
406        target = (uintptr_t)target >> 2;
407      }
408
409      if (checkoverflow(target, 26, raddr, " word", where, off)) {
410        return rtems_rtl_elf_rel_failure;
411      }
412
413      if (!parsing) {
414        target &= WIDTHMASK(26);
415        *insn = htole32((le32toh(*insn) & ~__BITS(25,0)) | target);
416      }
417
418      break;
419
420    case R_AARCH64_PREL32:
421      /*
422       * S + A - P
423       *  e.g.) 1: .word <sym>+<addend>-1b
424       */
425      if (!parsing) {
426        raddr = (Elf_Addr)symvalue + rela->r_addend;
427        target = raddr - (uintptr_t)where;
428        if (checkoverflow(target, 32, raddr, "", where, off)) {
429          return rtems_rtl_elf_rel_failure;
430        }
431        *where32 = target;
432      }
433      break;
434
435    case R_TYPE(TLSDESC):
436      printf ("rtl: reloc TLSDESC in %s --> %p in %s\n",
437              sect->name, (void *)*where,
438              rtems_rtl_obj_oname (obj));
439      break;
440
441    case R_TLS_TYPE(TLS_DTPREL):
442      printf ("rtl: reloc TLS_DTPREL in %s --> %p in %s\n",
443              sect->name, (void *)*where,
444              rtems_rtl_obj_oname (obj));
445      break;
446    case R_TLS_TYPE(TLS_DTPMOD):
447      printf ("rtl: reloc TLS_DTPMOD in %s --> %p in %s\n",
448              sect->name, (void *)*where,
449              rtems_rtl_obj_oname (obj));
450      break;
451
452    case R_TLS_TYPE(TLS_TPREL):
453      printf ("rtl: reloc TLS_TPREL in %s --> %p in %s\n",
454              sect->name, (void *)*where,
455              rtems_rtl_obj_oname (obj));
456      break;
457
458    default:
459      printf ("rtl: Unsupported relocation type in %s --> %p in %s\n",
460              sect->name, (void *)where,
461              rtems_rtl_obj_oname (obj));
462      return rtems_rtl_elf_rel_failure;
463  }
464
465  return rtems_rtl_elf_rel_no_error;
466}
467
468rtems_rtl_elf_rel_status
469rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
470                                   const Elf_Rela*           rela,
471                                   const rtems_rtl_obj_sect* sect,
472                                   const char*               symname,
473                                   const Elf_Byte            syminfo,
474                                   const Elf_Word            symvalue)
475{
476  return rtems_rtl_elf_reloc_rela (obj,
477                                   rela,
478                                   sect,
479                                   symname,
480                                   syminfo,
481                                   symvalue,
482                                   true);
483}
484
485rtems_rtl_elf_rel_status
486rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
487                             const Elf_Rela*           rela,
488                             const rtems_rtl_obj_sect* sect,
489                             const char*               symname,
490                             const Elf_Byte            syminfo,
491                             const Elf_Word            symvalue)
492{
493  return rtems_rtl_elf_reloc_rela (obj,
494                                   rela,
495                                   sect,
496                                   symname,
497                                   syminfo,
498                                   symvalue,
499                                   false);
500}
501
502rtems_rtl_elf_rel_status
503rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
504                                  const Elf_Rel*            rel,
505                                  const rtems_rtl_obj_sect* sect,
506                                  const char*               symname,
507                                  const Elf_Byte            syminfo,
508                                  const Elf_Word            symvalue)
509{
510  rtems_rtl_set_error (EINVAL, "rela type record not supported");
511  return rtems_rtl_elf_rel_failure;
512}
513
514rtems_rtl_elf_rel_status
515rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
516                            const Elf_Rel*            rel,
517                            const rtems_rtl_obj_sect* sect,
518                            const char*               symname,
519                            const Elf_Byte            syminfo,
520                            const Elf_Word            symvalue)
521{
522  rtems_rtl_set_error (EINVAL, "rela type record not supported");
523  return rtems_rtl_elf_rel_failure;
524}
525
526bool
527rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj,
528                            const char*          name,
529                            uint32_t             flags)
530{
531  /*
532   * We location the EH sections in section flags.
533   */
534  return false;
535}
536
537bool
538rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj)
539{
540  return true;
541}
542
543bool
544rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj)
545{
546  obj->loader = NULL;
547  return true;
548}
549
550/* An exception index table entry.  */
551typedef struct __EIT_entry
552{
553  _uw fnoffset;
554  _uw content;
555} __EIT_entry;
556
557/* The exception index table location in the base module */
558extern __EIT_entry __exidx_start;
559extern __EIT_entry __exidx_end;
560
561/*
562 * A weak reference is in libgcc, provide a real version and provide a way to
563 * manage loaded modules.
564 *
565 * Passed in the return address and a reference to the number of records
566 * found. We set the start of the exidx data and the number of records.
567 */
568_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address,
569                                     int*        nrec) __attribute__ ((__noinline__,
570                                                                       __used__,
571                                                                       __noclone__));
572
573_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address,
574                                     int*        nrec)
575{
576  rtems_rtl_data*   rtl;
577  rtems_chain_node* node;
578  __EIT_entry*      exidx_start = &__exidx_start;
579  __EIT_entry*      exidx_end = &__exidx_end;
580
581  rtl = rtems_rtl_lock ();
582
583  node = rtems_chain_first (&rtl->objects);
584  while (!rtems_chain_is_tail (&rtl->objects, node)) {
585    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
586    if (rtems_rtl_obj_text_inside (obj, (void*) return_address)) {
587      exidx_start = (__EIT_entry*) obj->eh_base;
588      exidx_end = (__EIT_entry*) (obj->eh_base + obj->eh_size);
589      break;
590    }
591    node = rtems_chain_next (node);
592  }
593
594  rtems_rtl_unlock ();
595
596  *nrec = exidx_end - exidx_start;
597
598  return (_Unwind_Ptr) exidx_start;
599}
Note: See TracBrowser for help on using the repository browser.