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

Last change on this file since 5500232 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: 16.6 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
77#include <rtems/rtl/rtl.h>
78#include "rtl-elf.h"
79#include "rtl-error.h"
80#include <rtems/rtl/rtl-trace.h>
81#include "rtl-unwind-arm.h"
82
83struct tls_data {
84  size_t    td_tlsindex;
85  Elf_Addr  td_tlsoffs;
86};
87
88rtems_rtl_elf_rel_status
89rtems_rtl_elf_reloc_rela (
90  rtems_rtl_obj*            obj,
91  const Elf_Rela*           rela,
92  const rtems_rtl_obj_sect* sect,
93  const char*               symname,
94  const Elf_Byte            syminfo,
95  const Elf_Word            symvalue,
96  const bool                parsing
97);
98
99#define __BITS(hi,lo) ((~((~(Elf_Addr)0)<<((hi)+1)))&((~(Elf_Addr)0)<<(lo)))
100#define WIDTHMASK(w) (0xffffffffffffffffUL >> (64 - (w)))
101
102static inline bool
103checkoverflow(Elf_Addr addr, int bitwidth, Elf_Addr targetaddr,
104    const char *bitscale, void *where, Elf64_Addr off)
105{
106  const Elf_Addr mask = ~__BITS(bitwidth - 1, 0);
107
108  if (((addr & mask) != 0) && ((addr & mask) != mask)) {
109    printf("kobj_reloc: Relocation 0x%jx too far from %p"
110        " (base+0x%jx) for %dbit%s\n",
111        (uintptr_t)targetaddr, where, off, bitwidth, bitscale);
112    return true;
113  }
114
115  return false;
116}
117
118static inline bool
119checkalign(Elf_Addr addr, int alignbyte, void *where, Elf64_Addr off)
120{
121  if ((addr & (alignbyte - 1)) != 0) {
122    printf("kobj_reloc: Relocation 0x%jx unaligned at %p"
123        " (base+0x%jx). must be aligned %d\n",
124        (uintptr_t)addr, where, off, alignbyte);
125    return true;
126  }
127  return false;
128}
129
130/*
131 * Set to 1 to allow untested relocations. If you tested one and it
132 * works or you fixed the relocation please remove the guard.
133 */
134#define ALLOW_UNTESTED_RELOCS 1
135
136static void*
137set_veneer(void* tramopline, Elf_Addr target)
138{
139  /*
140   * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
141   *
142   * ldr x9, #8
143   * br x9
144   *
145   */
146  uint64_t* tramp = (uint64_t*) tramopline;
147#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
148  *tramp++ = 0xd61f012058000049;
149#else
150  *tramp++ = 0xd61f012058000049; /* not tested */
151#endif
152  *tramp++ = (uint64_t) target;
153  return tramp;
154}
155
156static size_t
157get_veneer_size(int type)
158{
159  (void) type;
160  return 16;
161}
162
163size_t
164rtems_rtl_elf_relocate_tramp_max_size (void)
165{
166  return 16;
167}
168
169uint32_t
170rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
171                             const Elf_Shdr*      shdr)
172{
173  return 0;
174}
175
176uint32_t
177rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
178                                  int                  section,
179                                  const char*          name,
180                                  const Elf_Shdr*      shdr,
181                                  const uint32_t       flags)
182{
183  (void) obj;
184  (void) section;
185  (void) name;
186  (void) shdr;
187  return flags;
188}
189
190bool
191rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
192                                  rtems_rtl_obj_sect*  sect)
193{
194  (void) obj;
195  (void) sect;
196  return false;
197}
198
199bool
200rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
201                                 rtems_rtl_obj_sect*  sect)
202{
203  (void) obj;
204  (void) sect;
205  return false;
206}
207
208bool
209rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
210{
211  return true;
212}
213
214rtems_rtl_elf_rel_status
215rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
216                          const Elf_Rela*           rela,
217                          const rtems_rtl_obj_sect* sect,
218                          const char*               symname,
219                          const Elf_Byte            syminfo,
220                          const Elf_Word            symvalue,
221                          const bool                parsing)
222{
223  Elf64_Addr *where;
224  Elf32_Addr *where32;
225  Elf_Addr    off = rela->r_offset;
226  Elf_Addr    target;
227  Elf_Addr    raddr;
228  uint32_t   *insn, immhi, immlo, shift;
229
230  where = (Elf_Addr *)(sect->base + rela->r_offset);
231  where32 = (void *)where;
232
233  insn = (uint32_t *)where;
234
235  /*
236   * S - the address of the symbol
237   * A - the addend of the reolcation
238   * P - the address of the place being relocated (derived from r_offset)
239   * Page(expr) - the page address of the expression expr, defined as (expr & ~0xFFF).
240   */
241  switch (ELF_R_TYPE(rela->r_info)) {
242    case R_TYPE(NONE):
243      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
244        printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj));
245      }
246      break;
247
248    case R_TYPE(ABS64): /* word S + A */
249    case R_TYPE(GLOB_DAT): /* word S + A */
250      if (!parsing) {
251        target = (Elf_Addr)symvalue + rela->r_addend;
252
253        if (*where != target)
254          *where = target;
255
256        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
257          printf ("rtl: reloc 64/GLOB_DAT in %s --> %p in %s\n",
258                  sect->name, (void *)*where,
259                  rtems_rtl_obj_oname (obj));
260      }
261      break;
262
263    /*
264     * If S is a normal symbol, resolves to the difference between the static
265     * link address of S and the execution address of S. If S is the null symbol
266     * (ELF symbol index 0), resolves to the difference between the static link
267     * address of P and the execution address of P.
268     */
269    case R_TYPE(RELATIVE):  /* Delta(S) + A */
270      if (!parsing) {
271        *where = (Elf_Addr)(sect->base + rela->r_addend);
272        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
273          printf ("rtl: reloc RELATIVE in %s --> %p in %s\n",
274                  sect->name, (void *)*where,
275                  rtems_rtl_obj_oname (obj));
276      }
277      break;
278
279    case R_TYPE(COPY):
280      /*
281       * These are deferred until all other relocations have
282       * been done.  All we do here is make sure that the
283       * COPY relocation is not in a shared library.  They
284       * are allowed only in executable files.
285       */
286      printf("rtl: reloc COPY (please report)\n");
287      break;
288
289    case R_AARCH64_ADD_ABS_LO12_NC: /* S + A */
290    case R_AARCH64_LDST8_ABS_LO12_NC:
291    case R_AARCH_LDST16_ABS_LO12_NC:
292    case R_AARCH_LDST32_ABS_LO12_NC:
293    case R_AARCH_LDST64_ABS_LO12_NC:
294      switch (ELF_R_TYPE(rela->r_info)) {
295        case R_AARCH64_ADD_ABS_LO12_NC:
296        case R_AARCH64_LDST8_ABS_LO12_NC:
297          shift = 0;
298          break;
299        case R_AARCH_LDST16_ABS_LO12_NC:
300          shift = 1;
301          break;
302        case R_AARCH_LDST32_ABS_LO12_NC:
303          shift = 2;
304          break;
305        case R_AARCH_LDST64_ABS_LO12_NC:
306          shift = 3;
307          break;
308        default:
309          printf("illegal rtype: %ld\n", ELF_R_TYPE(rela->r_info));
310          break;
311      }
312
313      /*
314       * S + A
315       *  e.g.) add  x0,x0,#:lo12:<sym>+<addend>
316       *        ldrb w0,[x0,#:lo12:<sym>+<addend>]
317       *        ldrh w0,[x0,#:lo12:<sym>+<addend>]
318       *        ldr  w0,[x0,#:lo12:<sym>+<addend>]
319       *        ldr  x0,[x0,#:lo12:<sym>+<addend>]
320       */
321      if (!parsing) {
322        target = (Elf_Addr)symvalue + rela->r_addend;
323        if (checkalign(target, 1 << shift, where, off)) {
324          printf ("rtl: reloc checkalign failed in %s --> %p in %s\n",
325                  sect->name, (void *)*where,
326                  rtems_rtl_obj_oname (obj));
327          printf("ELF_R_TYPE is : %ld\n", ELF_R_TYPE(rela->r_info));
328          break;
329        }
330        target &= WIDTHMASK(12);
331        target >>= shift;
332        *insn = htole32(
333            (le32toh(*insn) & ~__BITS(21,10)) | (target << 10));
334      }
335      break;
336
337    case R_AARCH64_ADR_PREL_PG_HI21:
338      /*
339       * Page(S + A) - Page(P)
340       *  e.g.) adrp x0,<sym>+<addend>
341       */
342      if (!parsing) {
343        target = (Elf_Addr)symvalue + rela->r_addend;
344        target = target >> 12;
345        raddr = target << 12;
346        target -= (uintptr_t)where >> 12;
347
348        if (checkoverflow(target, 21, raddr, " x 4k", where, off)) {
349          return rtems_rtl_elf_rel_failure;
350        }
351
352        immlo = target & WIDTHMASK(2);
353        immhi = (target >> 2) & WIDTHMASK(19);
354        *insn = htole32((le32toh(*insn) &
355            ~(__BITS(30,29) | __BITS(23,5))) |
356            (immlo << 29) | (immhi << 5));
357      }
358      break;
359
360    case R_AARCH_JUMP26:
361    case R_AARCH_CALL26:
362      /*
363       * S + A - P
364       *  e.g.) b <sym>+<addend>
365       *        bl <sym>+<addend>
366       */
367      if (parsing && sect->base == 0) {
368        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
369          printf ("rtl: JUMP26/PC26/CALL tramp cache\n");
370        return rtems_rtl_elf_rel_tramp_cache;
371      }
372
373      raddr = (Elf_Addr)symvalue + rela->r_addend;
374      target = raddr - (uintptr_t)where;
375      if (checkalign(target, 4, where, off)) {
376        return rtems_rtl_elf_rel_failure;
377      }
378
379      target = (intptr_t)target >> 2;
380
381      if (((Elf_Sword)target > 0x1FFFFFF) || ((Elf_Sword)target < -0x2000000)) {
382        Elf_Word tramp_addr;
383        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
384
385        if (parsing) {
386          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
387            printf ("rtl: JUMP26/PC26/CALL tramp add\n");
388          return rtems_rtl_elf_rel_tramp_add;
389        }
390
391        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
392          rtems_rtl_set_error (EINVAL,
393                               "%s: CALL/JUMP26: overflow: no tramp memory",
394                               sect->name);
395          return rtems_rtl_elf_rel_failure;
396        }
397
398        tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
399        obj->tramp_brk = set_veneer(obj->tramp_brk, symvalue);
400
401        target = tramp_addr + rela->r_addend - (uintptr_t)where;
402        target = (uintptr_t)target >> 2;
403      }
404
405      if (checkoverflow(target, 26, raddr, " word", where, off)) {
406        return rtems_rtl_elf_rel_failure;
407      }
408
409      if (!parsing) {
410        target &= WIDTHMASK(26);
411        *insn = htole32((le32toh(*insn) & ~__BITS(25,0)) | target);
412      }
413
414      break;
415
416    case R_AARCH64_PREL32:
417      /*
418       * S + A - P
419       *  e.g.) 1: .word <sym>+<addend>-1b
420       */
421      if (!parsing) {
422        raddr = (Elf_Addr)symvalue + rela->r_addend;
423        target = raddr - (uintptr_t)where;
424        if (checkoverflow(target, 32, raddr, "", where, off)) {
425          return rtems_rtl_elf_rel_failure;
426        }
427        *where32 = target;
428      }
429      break;
430
431    case R_TYPE(TLSDESC):
432      printf ("rtl: reloc TLSDESC in %s --> %p in %s\n",
433              sect->name, (void *)*where,
434              rtems_rtl_obj_oname (obj));
435      break;
436
437    case R_TLS_TYPE(TLS_DTPREL):
438      printf ("rtl: reloc TLS_DTPREL in %s --> %p in %s\n",
439              sect->name, (void *)*where,
440              rtems_rtl_obj_oname (obj));
441      break;
442    case R_TLS_TYPE(TLS_DTPMOD):
443      printf ("rtl: reloc TLS_DTPMOD in %s --> %p in %s\n",
444              sect->name, (void *)*where,
445              rtems_rtl_obj_oname (obj));
446      break;
447
448    case R_TLS_TYPE(TLS_TPREL):
449      printf ("rtl: reloc TLS_TPREL in %s --> %p in %s\n",
450              sect->name, (void *)*where,
451              rtems_rtl_obj_oname (obj));
452      break;
453
454    default:
455      printf ("rtl: Unsupported relocation type in %s --> %p in %s\n",
456              sect->name, (void *)where,
457              rtems_rtl_obj_oname (obj));
458      return rtems_rtl_elf_rel_failure;
459  }
460
461  return rtems_rtl_elf_rel_no_error;
462}
463
464rtems_rtl_elf_rel_status
465rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
466                                   const Elf_Rela*           rela,
467                                   const rtems_rtl_obj_sect* sect,
468                                   const char*               symname,
469                                   const Elf_Byte            syminfo,
470                                   const Elf_Word            symvalue)
471{
472  return rtems_rtl_elf_reloc_rela (obj,
473                                   rela,
474                                   sect,
475                                   symname,
476                                   syminfo,
477                                   symvalue,
478                                   true);
479}
480
481rtems_rtl_elf_rel_status
482rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
483                             const Elf_Rela*           rela,
484                             const rtems_rtl_obj_sect* sect,
485                             const char*               symname,
486                             const Elf_Byte            syminfo,
487                             const Elf_Word            symvalue)
488{
489  return rtems_rtl_elf_reloc_rela (obj,
490                                   rela,
491                                   sect,
492                                   symname,
493                                   syminfo,
494                                   symvalue,
495                                   false);
496}
497
498rtems_rtl_elf_rel_status
499rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
500                                  const Elf_Rel*            rel,
501                                  const rtems_rtl_obj_sect* sect,
502                                  const char*               symname,
503                                  const Elf_Byte            syminfo,
504                                  const Elf_Word            symvalue)
505{
506  rtems_rtl_set_error (EINVAL, "rela type record not supported");
507  return rtems_rtl_elf_rel_failure;
508}
509
510rtems_rtl_elf_rel_status
511rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
512                            const Elf_Rel*            rel,
513                            const rtems_rtl_obj_sect* sect,
514                            const char*               symname,
515                            const Elf_Byte            syminfo,
516                            const Elf_Word            symvalue)
517{
518  rtems_rtl_set_error (EINVAL, "rela type record not supported");
519  return rtems_rtl_elf_rel_failure;
520}
Note: See TracBrowser for help on using the repository browser.