source: rtems/cpukit/libdl/rtl-mdreloc-powerpc.c

Last change on this file was b9f11607, checked in by Chris Johns <chrisj@…>, on 08/21/23 at 01:15:13

libdl: Realloc text memory if there are trampolines

  • Add resize to the allocator interface
  • Rework the trampoline variables in the obj struct to make better sense of what is happening

Closes #4944

  • Property mode set to 100644
File size: 18.0 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 *  @file
5 *
6 *  @ingroup
7 *
8 *  @brief
9 */
10
11/*
12 * Copyright (C) 2014 Chris Johns <chrisj@rtems.org>.
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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * 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 * Taken from NetBSD and stripped of the relocations not needed on RTEMS.
38 */
39
40/*  $NetBSD: ppc_reloc.c,v 1.44 2010/01/13 20:17:22 christos Exp $  */
41
42#include <sys/cdefs.h>
43
44#include <errno.h>
45#include <inttypes.h>
46#include <stdio.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49
50#include <rtems/rtl/rtl.h>
51#include "rtl-bit-alloc.h"
52#include "rtl-elf.h"
53#include "rtl-error.h"
54#include <rtems/rtl/rtl-trace.h>
55#include "rtl-unwind.h"
56#include "rtl-unwind-dw2.h"
57
58#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
59                 ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
60#define l(x) ((u_int32_t)(x) & 0xffff)
61
62/*
63 * SDATA allocator.
64 */
65static rtems_rtl_bit_alloc* sdata;
66
67static Elf_Addr
68get_sda_base (void)
69{
70  uint32_t sda_base;
71  __asm__ volatile (" mr %0, 13\n" : "=r" (sda_base));
72  return sda_base;
73}
74
75/*
76 *  Access the variables via asm statements to avoid any fix up issues
77 *  generated by the C compiler which thinks they belong in the .sdata
78 *  section.
79 */
80
81#define GET_ADDR(_l, _v) \
82  __asm__ volatile (" lis %0, " #_l "@h\n" \
83                    " ori %0, %0, " #_l "@l\n" : "=r" (_v))
84
85static void*
86get_sdata_start (void)
87{
88#if _ARCH_PPC64
89  return NULL;
90#else
91  Elf_Addr addr;
92  GET_ADDR(__SDATA_START__, addr);
93  return (void*) addr;
94#endif
95}
96
97#if !_ARCH_PPC64
98static size_t
99get_sdata_sbss_size (void)
100{
101  Elf_Addr sdata_begin;
102  Elf_Addr sbss_end;
103  GET_ADDR(bsp_section_sdata_begin, sdata_begin);
104  GET_ADDR(bsp_section_sbss_end, sbss_end);
105  return sbss_end - sdata_begin;
106}
107
108static size_t
109get_sdata_libdl_size (void)
110{
111  Elf_Addr begin;
112  Elf_Addr end;
113  GET_ADDR(bsp_section_sdata_libdl_begin, begin);
114  GET_ADDR(bsp_section_sdata_libdl_end, end);
115  return end - begin;
116}
117#endif
118
119uint32_t
120rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
121                             const Elf_Shdr*      shdr)
122{
123  return 0;
124}
125
126uint32_t
127rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
128                                  int                  section,
129                                  const char*          name,
130                                  const Elf_Shdr*      shdr,
131                                  const uint32_t       flags)
132{
133#if !_ARCH_PPC64
134  struct {
135    const char* label;
136    size_t      len;
137  } prefix[] = {
138    #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 }
139    SEPARATED_PREFIX (".sdata"),
140    SEPARATED_PREFIX (".sbss"),
141  };
142  const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]);
143  size_t       p;
144  for (p = 0; p < prefixes; ++p)
145  {
146    if (strncmp (name, prefix[p].label, prefix[p].len) == 0)
147      return flags | RTEMS_RTL_OBJ_SECT_ARCH_ALLOC;
148  }
149#endif
150  return flags;
151}
152
153bool
154rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
155                                  rtems_rtl_obj_sect*  sect)
156{
157#if _ARCH_PPC64
158    rtems_rtl_set_error (ENOMEM, ".sdata no supported by ABI");
159    return false;
160#else
161  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
162    printf ("rtl: section: arch: alloc: name=%s size=%zu flags=%08" PRIx32 \
163            " order=%i link=%d info=%d\n",
164            sect->name, sect->size, sect->flags, sect->load_order,
165            sect->link, sect->info);
166
167  if (sdata == NULL)
168  {
169    sdata = rtems_rtl_bit_alloc_open (get_sdata_start (),
170                                      get_sdata_libdl_size (),
171                                      sizeof (uint32_t),
172                                      get_sdata_sbss_size ());
173    if (sdata == NULL)
174    {
175      rtems_rtl_set_error (ENOMEM, "no memory for sdata allocator");
176      return false;
177    }
178  }
179
180  sect->base = rtems_rtl_bit_alloc_balloc (sdata, sect->size);
181  if (sect->base == NULL)
182  {
183    rtems_rtl_set_error (ENOMEM, "no .sdata memory: %s", sect->name);
184    return false;
185  }
186
187  return true;
188#endif
189}
190
191bool
192rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
193                                  rtems_rtl_obj_sect*  sect)
194{
195#if !_ARCH_PPC64
196  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
197    printf ("rtl: section: arch: free: name=%s size=%zu\n", sect->name, sect->size);
198  if (sdata != NULL)
199    rtems_rtl_bit_alloc_bfree (sdata, sect->base, sect->size);
200#endif
201  return true;
202}
203
204bool
205rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
206{
207  return true;
208}
209
210uint32_t rtems_rtl_obj_tramp_alignment (const rtems_rtl_obj* obj)
211{
212  (void) obj;
213  return sizeof(uint32_t);
214}
215
216size_t
217rtems_rtl_elf_relocate_tramp_max_size (void)
218{
219  /*
220   * We have 4 instructions and each instruction is 32bits.
221   */
222  return 4 * 4;
223}
224
225static void*
226set_veneer (void* tramopline, Elf_Addr target)
227{
228  /*
229   * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
230   *
231   *  lis   12,0x1234
232   *  ori   12,12,0x5678
233   *  mtctr 12
234   *  bctr
235   */
236#if COMPILE_ASM
237  asm volatile (" lis   12,0x1234\n" \
238                " ori   12,12,0x5678\n" \
239                " mtctr 12\n" \
240                " bctr\n");
241#endif
242  uint32_t* tramp = (uint32_t*) tramopline;
243  *tramp++ = 0x3d800000 | (target >> 16);
244  *tramp++ = 0x618c0000 | (target & 0xffff);
245  *tramp++ = 0x7d8903a6;
246  *tramp++ = 0x4e800420;
247  return tramp;
248}
249
250static size_t
251get_veneer_size (int type)
252{
253  (void) type;
254  return rtems_rtl_elf_relocate_tramp_max_size ();
255}
256
257/**
258 * The offsets in the reloc words.
259 */
260#define REL_R_OFFSET (0)
261#define REL_R_INFO   (1)
262#define REL_R_ADDEND (2)
263
264static rtems_rtl_elf_rel_status
265rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
266                          const Elf_Rela*           rela,
267                          const rtems_rtl_obj_sect* sect,
268                          const char*               symname,
269                          const Elf_Byte            syminfo,
270                          const Elf_Word            symvalue,
271                          const bool                parsing)
272{
273  Elf_Addr* where;
274  Elf_Word tmp;
275  uint32_t mask = 0;
276  uint32_t bits = 0;
277  bool     needs_tramp = false;
278
279  where = (Elf_Addr *)(sect->base + rela->r_offset);
280  switch (ELF_R_TYPE(rela->r_info)) {
281    case R_TYPE(NONE):
282      break;
283
284    case R_TYPE(32):
285      /*
286       * value:1; Field: word32; Expression: S + A
287       */
288      if (!parsing) {
289        *where = symvalue + rela->r_addend;
290        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
291          printf ("rtl: ADDR32 %p @ %p in %s\n",
292                  (void *)*(where), where, rtems_rtl_obj_oname (obj));
293      }
294      break;
295
296    case R_TYPE(14):
297      /*
298       * value:7; Field: low14*; Expression: (S + A) >> 2
299       */
300    case R_TYPE(24):
301      /*
302       * value:2; Field: low24*; Expression: (S + A) >> 2
303       */
304      if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) {
305        bits = 14;
306        mask = 0xfffc;
307      } else {
308        bits = 24;
309        mask = 0x3fffffc;
310      }
311
312      if (parsing && sect->base == 0) {
313        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
314          printf ("rtl: ADDR14/ADDR24 tramp cache\n");
315        return rtems_rtl_elf_rel_tramp_cache;
316      }
317
318      tmp = (symvalue + rela->r_addend) >> 2;
319      if (tmp > ((1<<bits) - 1 )) {
320        Elf_Word tramp_addr;
321        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
322        if (parsing) {
323          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
324            printf ("rtl: ADDR14/ADDR24 tramp add\n");
325          return rtems_rtl_elf_rel_tramp_add;
326        }
327        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
328          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
329            printf ("rtl: ADDR14/ADDR24 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
330          rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: ADDR14/ADDR24", sect->name);
331          return rtems_rtl_elf_rel_failure;
332        }
333        needs_tramp = true;
334        tramp_addr = (Elf_Addr) obj->tramp_brk;
335        obj->tramp_brk = set_veneer(obj->tramp_brk,
336                                    symvalue + rela->r_addend);
337        tmp = *where;
338        tmp &= ~mask;
339        tmp |= (tramp_addr + rela->r_addend) & mask;
340      }
341      else {
342        tmp = *where;
343        tmp &= ~mask;
344        tmp |= (symvalue + rela->r_addend) & mask;
345      }
346
347      if (!parsing) {
348        *where = tmp;
349        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
350          printf ("rtl: ADDR14/ADDR24%s %p @ %p in %s\n",
351                  needs_tramp ? "(tramp)" : "",
352                  (void *)*where, where, rtems_rtl_obj_oname (obj));
353      }
354      break;
355
356    case R_TYPE(16_HA):
357    case R_TYPE(TPREL16_HA):
358      /*
359       * value:6; Field:half16; Expression: #ha(S+A)
360       * value:72; Field:half16; Expression: #ha(S+A)
361       */
362      if (!parsing) {
363        tmp = symvalue + rela->r_addend;
364        *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
365        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
366          printf ("rtl: %s16_HA %p @ %p in %s\n",
367                  ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HA) ? "TPREL" : "",
368                  (void *)*(where), where, rtems_rtl_obj_oname (obj));
369      }
370      break;
371
372    case R_TYPE(16_HI):
373    case R_TYPE(TPREL16_HI):
374      /*
375       * value:5; Field:half16; Expression: #hi(S+A)
376       * value:71; Field:half16; Expression: #hi(S+A)
377       */
378      if (!parsing) {
379        *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
380        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
381          printf ("rtl: %s16_HI %p @ %p in %s\n",
382                  ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_HI) ? "TPREL" : "",
383                  (void *)*where, where, rtems_rtl_obj_oname (obj));
384      }
385      break;
386
387    case R_TYPE(16_LO):
388    case R_TYPE(TPREL16_LO):
389      /*
390       * value:4; Field:half16; Expression: #lo(S+A)
391       * value:71; Field:half16; Expression: #lo(S+A)
392       */
393      if (!parsing) {
394        *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
395        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
396          printf ("rtl: %s16_LO %p @ %p in %s\n",
397                  ELF_R_TYPE(rela->r_info) == R_TYPE(TPREL16_LO) ? "TPREL" : "",
398                  (void *)*where, where, rtems_rtl_obj_oname (obj));
399      }
400      break;
401
402    case R_TYPE(REL14):
403      /*
404       * value:11; Field:low14*; Expression:(S+A-P)>>2
405       */
406    case R_TYPE(REL24):
407      /*
408       * value:10; Field:low24*; Expression:(S+A-P)>>2
409       */
410      if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) {
411        mask = 0x3fffffc;
412        bits = 24;
413      }
414      else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) {
415        mask = 0xfffc;
416        bits = 14;
417      }
418
419      if (parsing && sect->base == 0) {
420        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
421          printf ("rtl: REL24/REL14 tramp cache\n");
422        return rtems_rtl_elf_rel_tramp_cache;
423      }
424
425      tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
426      if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
427          ((Elf_Sword)tmp < -(1<<(bits-1)))) {
428        Elf_Word tramp_addr;
429        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
430        if (parsing) {
431          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
432            printf ("rtl: REL24/REL14 tramp add\n");
433          return rtems_rtl_elf_rel_tramp_add;
434        }
435        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
436          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
437            printf ("rtl: REL24/REL14 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
438          rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: REL24/REL14", sect->name);
439          return rtems_rtl_elf_rel_failure;
440        }
441        needs_tramp = true;
442        tramp_addr = (Elf_Addr) obj->tramp_brk;
443        obj->tramp_brk = set_veneer(obj->tramp_brk,
444                                    symvalue + rela->r_addend);
445        tmp = *where;
446        tmp &= ~mask;
447        tmp |= (tramp_addr + rela->r_addend - (Elf_Addr)where) & mask;
448      }
449      else
450      {
451        tmp = *where;
452        tmp &= ~mask;
453        tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
454      }
455
456      if (!parsing) {
457        *where = tmp;
458        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
459          printf ("rtl: REL24/REL14%s %p @ %p in %s\n",
460                  needs_tramp ? "(tramp)" : "",
461                  (void *)*where, where, rtems_rtl_obj_oname (obj));
462      }
463      break;
464
465    case R_TYPE(REL32):
466      /*
467       * value:26; Field:word32*; Expression:S+A-P
468       */
469      if (!parsing) {
470        *where = symvalue + rela->r_addend - (Elf_Addr)where;
471        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
472          printf ("rtl: REL32 %p @ %p in %s\n",
473                  (void *)*where, where, rtems_rtl_obj_oname (obj));
474      }
475      break;
476
477    case R_TYPE(SDAREL16):
478      /*
479       * A sign-extended 16 bit value relative to _SDA_BASE_, for use with
480       * small data items.
481       */
482      if (!parsing) {
483        Elf_Addr sda_base = get_sda_base ();
484        mask = 0xffff;
485        tmp = *((Elf32_Half*) where);
486        tmp &= ~mask;
487        tmp |= (symvalue + rela->r_addend - sda_base) & mask;
488        *((Elf32_Half*) where) = tmp;
489        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
490          printf ("rtl: SDAREL16 %p @ %p in %s\n",
491                  (void *) (uintptr_t) *((Elf32_Half*) where),
492                  where, rtems_rtl_obj_oname (obj));
493      }
494      break;
495
496    default:
497      printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, "
498              "contents = %p\n",
499              ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
500              (void *)rela->r_offset, (void *)*where);
501      rtems_rtl_set_error (EINVAL,
502                           "%s: Unsupported relocation type %" PRId32
503                           " in non-PLT relocations",
504                           sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
505      return rtems_rtl_elf_rel_failure;
506  }
507  return rtems_rtl_elf_rel_no_error;
508}
509
510rtems_rtl_elf_rel_status
511rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
512                                   const Elf_Rela*           rela,
513                                   const rtems_rtl_obj_sect* sect,
514                                   const char*               symname,
515                                   const Elf_Byte            syminfo,
516                                   const Elf_Word            symvalue)
517{
518  return rtems_rtl_elf_reloc_rela (obj,
519                                   rela,
520                                   sect,
521                                   symname,
522                                   syminfo,
523                                   symvalue,
524                                   true);
525}
526
527rtems_rtl_elf_rel_status
528rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
529                             const Elf_Rela*           rela,
530                             const rtems_rtl_obj_sect* sect,
531                             const char*               symname,
532                             const Elf_Byte            syminfo,
533                             const Elf_Word            symvalue)
534{
535  return rtems_rtl_elf_reloc_rela (obj,
536                                   rela,
537                                   sect,
538                                   symname,
539                                   syminfo,
540                                   symvalue,
541                                   false);
542}
543
544rtems_rtl_elf_rel_status
545rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
546                                  const Elf_Rel*            rel,
547                                  const rtems_rtl_obj_sect* sect,
548                                  const char*               symname,
549                                  const Elf_Byte            syminfo,
550                                  const Elf_Word            symvalue)
551{
552  (void) obj;
553  (void) rel;
554  (void) sect;
555  (void) symname;
556  (void) syminfo;
557  (void) symvalue;
558  rtems_rtl_set_error (EINVAL, "rel type record not supported");
559  return rtems_rtl_elf_rel_failure;
560}
561
562rtems_rtl_elf_rel_status
563rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
564                            const Elf_Rel*            rel,
565                            const rtems_rtl_obj_sect* sect,
566                            const char*               symname,
567                            const Elf_Byte            syminfo,
568                            const Elf_Word            symvalue)
569{
570  (void) obj;
571  (void) rel;
572  (void) sect;
573  (void) symname;
574  (void) syminfo;
575  (void) symvalue;
576  rtems_rtl_set_error (EINVAL, "rel type record not supported");
577  return rtems_rtl_elf_rel_failure;
578}
579
580bool
581rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj,
582                            const char*          name,
583                            uint32_t             flags)
584{
585  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
586}
587
588bool
589rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj)
590{
591  return rtems_rtl_elf_unwind_dw2_register (obj);
592}
593
594bool
595rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj)
596{
597  return rtems_rtl_elf_unwind_dw2_deregister (obj);
598}
Note: See TracBrowser for help on using the repository browser.