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

Last change on this file since b36c5209 was b36c5209, checked in by Chris Johns <chrisj@…>, on May 3, 2019 at 12:15:20 AM

libdl: Do not access the ELF file while the allocator is locked.

  • Load symbols before allocation.
  • Parse reloc records and place any reloc recs in a cache to use while the allocator is locked.
  • Relocate symbols after section allocation.
  • Split section loading into allocation/locating and loading.
  • Update all arch back-ends with a new reloc interface to control tramp handling.
  • Add -a and -t to the object list shell command.

Closes #3741

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