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

5
Last change on this file since 6c9f017 was 6c9f017, checked in by Chris Johns <chrisj@…>, on 02/02/19 at 04:09:53

libdl: Add powerpc large memory and small data support.

  • Add support for architecure sections that can be handled by the architecture back end.
  • Add trampoline/fixup support for PowerPC. This means the PowerPC now supports large memory loading of applications.
  • Add a bit allocator to manage small block based regions of memory.
  • Add small data (sdata/sbss) support for the PowerPC. The support makes the linker allocated small data region of memory a global resource available to libdl loaded object files.

Updates #3687
Updates #3685

  • Property mode set to 100644
File size: 14.0 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  Elf_Addr addr;
54  GET_ADDR(__SDATA_START__, addr);
55  return (void*) addr;
56}
57
58static size_t
59get_sdata_sbss_size (void)
60{
61  Elf_Addr sdata_begin;
62  Elf_Addr sbss_end;
63  GET_ADDR(bsp_section_sdata_begin, sdata_begin);
64  GET_ADDR(bsp_section_sbss_end, sbss_end);
65  return sbss_end - sdata_begin;
66}
67
68static size_t
69get_sdata_libdl_size (void)
70{
71  Elf_Addr begin;
72  Elf_Addr end;
73  GET_ADDR(bsp_section_sdata_libdl_begin, begin);
74  GET_ADDR(bsp_section_sdata_libdl_end, end);
75  return end - begin;
76}
77
78uint32_t
79rtems_rtl_elf_section_flags (const rtems_rtl_obj* obj,
80                             const Elf_Shdr*      shdr)
81{
82  return 0;
83}
84
85uint32_t
86rtems_rtl_elf_arch_parse_section (const rtems_rtl_obj* obj,
87                                  int                  section,
88                                  const char*          name,
89                                  const Elf_Shdr*      shdr,
90                                  const uint32_t       flags)
91{
92  struct {
93    const char* label;
94    size_t      len;
95  } prefix[] = {
96    #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 }
97    SEPARATED_PREFIX (".sdata"),
98    SEPARATED_PREFIX (".sbss"),
99  };
100  const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]);
101  size_t       p;
102  for (p = 0; p < prefixes; ++p)
103  {
104    if (strncmp (name, prefix[p].label, prefix[p].len) == 0)
105      return flags | RTEMS_RTL_OBJ_SECT_ARCH_ALLOC;
106  }
107  return flags;
108}
109
110bool
111rtems_rtl_elf_arch_section_alloc (const rtems_rtl_obj* obj,
112                                  rtems_rtl_obj_sect*  sect)
113{
114  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
115    printf ("rtl: section: arch: alloc: name=%s size=%zu flags=%08" PRIx32 \
116            " order=%i link=%d info=%d\n",
117            sect->name, sect->size, sect->flags, sect->load_order,
118            sect->link, sect->info);
119
120  if (sdata == NULL)
121  {
122    sdata = rtems_rtl_bit_alloc_open (get_sdata_start (),
123                                      get_sdata_libdl_size (),
124                                      sizeof (uint32_t),
125                                      get_sdata_sbss_size ());
126    if (sdata == NULL)
127    {
128      rtems_rtl_set_error (ENOMEM, "no memory for sdata allocator");
129      return false;
130    }
131  }
132
133  sect->base = rtems_rtl_bit_alloc_balloc (sdata, sect->size);
134  if (sect->base == NULL)
135  {
136    rtems_rtl_set_error (ENOMEM, "no .sdata memory: %s", sect->name);
137    return false;
138  }
139
140  return true;
141}
142
143bool
144rtems_rtl_elf_arch_section_free (const rtems_rtl_obj* obj,
145                                  rtems_rtl_obj_sect*  sect)
146{
147  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
148    printf ("rtl: section: arch: free: name=%s size=%zu\n", sect->name, sect->size);
149  if (sdata != NULL)
150    rtems_rtl_bit_alloc_bfree (sdata, sect->base, sect->size);
151  return true;
152}
153
154bool
155rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
156{
157  return true;
158}
159
160size_t
161rtems_rtl_elf_relocate_tramp_max_size (void)
162{
163  /*
164   * We have 4 instructions and each instruction is 32bits.
165   */
166  return 4 * 4;
167}
168
169static void*
170set_veneer (void* tramopline, Elf_Addr target)
171{
172  /*
173   * http://shell-storm.org/online/Online-Assembler-and-Disassembler/
174   *
175   *  lis   12,0x1234
176   *  ori   12,12,0x5678
177   *  mtctr 12
178   *  bctr
179   */
180#if COMPILE_ASM
181  asm volatile (" lis   12,0x1234\n" \
182                " ori   12,12,0x5678\n" \
183                " mtctr 12\n" \
184                " bctr\n");
185#endif
186  uint32_t* tramp = (uint32_t*) tramopline;
187  *tramp++ = 0x3d800000 | (target >> 16);
188  *tramp++ = 0x618c0000 | (target & 0xffff);
189  *tramp++ = 0x7d8903a6;
190  *tramp++ = 0x4e800420;
191  return tramp;
192}
193
194static size_t
195get_veneer_size (int type)
196{
197  (void) type;
198  return rtems_rtl_elf_relocate_tramp_max_size ();
199}
200
201static bool
202rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
203                          const Elf_Rela*           rela,
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_Word tmp;
212  uint32_t mask = 0;
213  uint32_t bits = 0;
214
215  where = (Elf_Addr *)(sect->base + rela->r_offset);
216  switch (ELF_R_TYPE(rela->r_info)) {
217    case R_TYPE(NONE):
218      break;
219
220    case R_TYPE(32):
221      /*
222       * value:1; Field: word32; Expression: S + A
223       */
224      if (!parsing) {
225        *where = symvalue + rela->r_addend;
226        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
227          printf ("rtl: ADDR32 %p @ %p in %s\n",
228                  (void *)*(where), where, rtems_rtl_obj_oname (obj));
229      }
230      break;
231
232    case R_TYPE(14):
233      /*
234       * value:7; Field: low14*; Expression: (S + A) >> 2
235       */
236    case R_TYPE(24):
237      /*
238       * value:2; Field: low24*; Expression: (S + A) >> 2
239       */
240      if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) {
241        bits = 14;
242        mask = 0xfffc;
243      } else {
244        bits = 24;
245        mask = 0x3fffffc;
246      }
247      tmp = (symvalue + rela->r_addend) >> 2;
248      if (tmp > ((1<<bits) - 1 )) {
249        Elf_Word tramp_addr;
250        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
251        if (parsing) {
252          obj->tramp_size += tramp_size;
253          return true;
254        }
255        tramp_addr = (Elf_Addr) obj->tramp_brk;
256        obj->tramp_brk = set_veneer(obj->tramp_brk,
257                                    symvalue + rela->r_addend);
258        tmp = *where;
259        tmp &= ~mask;
260        tmp |= (tramp_addr + rela->r_addend) & mask;
261      }
262      else {
263        tmp = *where;
264        tmp &= ~mask;
265        tmp |= (symvalue + rela->r_addend) & mask;
266      }
267
268      if (!parsing) {
269        *where = tmp;
270        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
271          printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n",
272                  (void *)*where, where, rtems_rtl_obj_oname (obj));
273      }
274      break;
275
276    case R_TYPE(16_HA):
277      /*
278       * value:6; Field:half16; Expression: #ha(S+A)
279       */
280      if (!parsing) {
281        tmp = symvalue + rela->r_addend;
282        *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
283        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
284          printf ("rtl: 16_HA %p @ %p in %s\n",
285                  (void *)*(where), where, rtems_rtl_obj_oname (obj));
286      }
287      break;
288
289    case R_TYPE(16_HI):
290      /*
291       * value:5; Field:half16; Expression: #hi(S+A)
292       */
293      if (!parsing) {
294        *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
295        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
296          printf ("rtl: 16_HI %p @ %p in %s\n",
297                  (void *)*where, where, rtems_rtl_obj_oname (obj));
298      }
299      break;
300    case R_TYPE(16_LO):
301      /*
302       * value:4; Field:half16; Expression: #lo(S+A)
303       */
304      if (!parsing) {
305        *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
306        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
307          printf ("rtl: 16_LO %p @ %p in %s\n",
308                  (void *)*where, where, rtems_rtl_obj_oname (obj));
309      }
310      break;
311
312    case R_TYPE(REL14):
313      /*
314       * value:11; Field:low14*; Expression:(S+A-P)>>2
315       */
316    case R_TYPE(REL24):
317      /*
318       * value:10; Field:low24*; Expression:(S+A-P)>>2
319       */
320      if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) {
321        mask = 0x3fffffc;
322        bits = 24;
323      }
324      else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) {
325        mask = 0xfffc;
326        bits = 14;
327      }
328
329      tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
330      if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
331          ((Elf_Sword)tmp < -(1<<(bits-1)))) {
332        Elf_Word tramp_addr;
333        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
334        if (parsing) {
335          obj->tramp_size += tramp_size;
336          return true;
337        }
338        tramp_addr = (Elf_Addr) obj->tramp_brk;
339        obj->tramp_brk = set_veneer(obj->tramp_brk,
340                                    symvalue + rela->r_addend);
341        tmp = *where;
342        tmp &= ~mask;
343        tmp |= (tramp_addr + rela->r_addend - (Elf_Addr)where) & mask;
344      }
345      else
346      {
347        tmp = *where;
348        tmp &= ~mask;
349        tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
350      }
351
352      if (!parsing) {
353        *where = tmp;
354        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
355          printf ("rtl: REL24/REL14 %p @ %p in %s\n",
356                  (void *)*where, where, rtems_rtl_obj_oname (obj));
357      }
358      break;
359
360    case R_TYPE(REL32):
361      /*
362       * value:26; Field:word32*; Expression:S+A-P
363       */
364      if (!parsing) {
365        *where = symvalue + rela->r_addend - (Elf_Addr)where;
366        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
367          printf ("rtl: REL32 %p @ %p in %s\n",
368                  (void *)*where, where, rtems_rtl_obj_oname (obj));
369      }
370      break;
371
372    case R_TYPE(SDAREL16):
373      /*
374       * A sign-extended 16 bit value relative to _SDA_BASE_, for use with
375       * small data items.
376       */
377      if (!parsing) {
378        Elf_Addr sda_base = get_sda_base ();
379        mask = 0xffff;
380        tmp = *((Elf32_Half*) where);
381        tmp &= ~mask;
382        tmp |= (symvalue + rela->r_addend - sda_base) & mask;
383        *((Elf32_Half*) where) = tmp;
384        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
385          printf ("rtl: SDAREL16 %p @ %p in %s\n",
386                  (void *) (uintptr_t) *((Elf32_Half*) where),
387                  where, rtems_rtl_obj_oname (obj));
388      }
389      break;
390
391    default:
392      printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, "
393              "contents = %p\n",
394              ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
395              (void *)rela->r_offset, (void *)*where);
396      rtems_rtl_set_error (EINVAL,
397                           "%s: Unsupported relocation type %" PRId32
398                           "in non-PLT relocations",
399                           sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
400      return false;
401  }
402  return true;
403}
404
405bool
406rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
407                                   const Elf_Rela*           rela,
408                                   const rtems_rtl_obj_sect* sect,
409                                   const char*               symname,
410                                   const Elf_Byte            syminfo,
411                                   const Elf_Word            symvalue)
412{
413  return rtems_rtl_elf_reloc_rela (obj,
414                                   rela,
415                                   sect,
416                                   symname,
417                                   syminfo,
418                                   symvalue,
419                                   true);
420}
421
422bool
423rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
424                             const Elf_Rela*           rela,
425                             const rtems_rtl_obj_sect* sect,
426                             const char*               symname,
427                             const Elf_Byte            syminfo,
428                             const Elf_Word            symvalue)
429{
430  return rtems_rtl_elf_reloc_rela (obj,
431                                   rela,
432                                   sect,
433                                   symname,
434                                   syminfo,
435                                   symvalue,
436                                   false);
437}
438
439bool
440rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
441                                  const Elf_Rel*            rel,
442                                  const rtems_rtl_obj_sect* sect,
443                                  const char*               symname,
444                                  const Elf_Byte            syminfo,
445                                  const Elf_Word            symvalue)
446{
447  (void) obj;
448  (void) rel;
449  (void) sect;
450  (void) symname;
451  (void) syminfo;
452  (void) symvalue;
453  rtems_rtl_set_error (EINVAL, "rel type record not supported");
454  return false;
455}
456
457bool
458rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
459                            const Elf_Rel*            rel,
460                            const rtems_rtl_obj_sect* sect,
461                            const char*               symname,
462                            const Elf_Byte            syminfo,
463                            const Elf_Word            symvalue)
464{
465  (void) obj;
466  (void) rel;
467  (void) sect;
468  (void) symname;
469  (void) syminfo;
470  (void) symvalue;
471  rtems_rtl_set_error (EINVAL, "rel type record not supported");
472  return false;
473}
474
475bool
476rtems_rtl_elf_unwind_parse (const rtems_rtl_obj* obj,
477                            const char*          name,
478                            uint32_t             flags)
479{
480  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
481}
482
483bool
484rtems_rtl_elf_unwind_register (rtems_rtl_obj* obj)
485{
486  return rtems_rtl_elf_unwind_dw2_register (obj);
487}
488
489bool
490rtems_rtl_elf_unwind_deregister (rtems_rtl_obj* obj)
491{
492  return rtems_rtl_elf_unwind_dw2_deregister (obj);
493}
Note: See TracBrowser for help on using the repository browser.