summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl/rtl-mdreloc-powerpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl/rtl-mdreloc-powerpc.c')
-rw-r--r--cpukit/libdl/rtl-mdreloc-powerpc.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/cpukit/libdl/rtl-mdreloc-powerpc.c b/cpukit/libdl/rtl-mdreloc-powerpc.c
new file mode 100644
index 0000000000..d1c0a4fa4e
--- /dev/null
+++ b/cpukit/libdl/rtl-mdreloc-powerpc.c
@@ -0,0 +1,186 @@
+/*
+ * Taken from NetBSD and stripped of the relocations not needed on RTEMS.
+ */
+
+/* $NetBSD: ppc_reloc.c,v 1.44 2010/01/13 20:17:22 christos Exp $ */
+
+#include <sys/cdefs.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <rtems/rtl/rtl.h>
+#include "rtl-elf.h"
+#include "rtl-error.h"
+#include "rtl-trace.h"
+
+#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
+ ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
+#define l(x) ((u_int32_t)(x) & 0xffff)
+
+
+bool
+rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
+{
+ return true;
+}
+
+bool
+rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj,
+ const Elf_Rela* rela,
+ const rtems_rtl_obj_sect_t* sect,
+ const char* symname,
+ const Elf_Byte syminfo,
+ const Elf_Word symvalue)
+{
+ Elf_Addr target = 0;
+ Elf_Addr* where;
+ Elf_Word tmp;
+ uint32_t mask = 0;
+ uint32_t bits = 0;
+
+ where = (Elf_Addr *)(sect->base + rela->r_offset);
+ switch (ELF_R_TYPE(rela->r_info)) {
+ case R_TYPE(NONE):
+ break;
+
+ case R_TYPE(32):
+ /*
+ * value:1; Field: word32; Expression: S + A
+ */
+ *where = symvalue + rela->r_addend;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: ADDR32 %p @ %p in %s\n",
+ (void *)*(where), where, rtems_rtl_obj_oname (obj));
+ break;
+
+ case R_TYPE(14):
+ /*
+ * value:7; Field: low14*; Expression: (S + A) >> 2
+ */
+ case R_TYPE(24):
+ /*
+ * value:2; Field: low24*; Expression: (S + A) >> 2
+ */
+ if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) {
+ bits = 14;
+ mask = 0xfffc;
+ } else {
+ bits = 24;
+ mask = 0x3fffffc;
+ }
+ tmp = (symvalue + rela->r_addend) >> 2;
+ if (tmp > (1<<bits -1 )) {
+ printf("Overflow ADDR14/ADDR24\n");
+ return false;
+ }
+ tmp = *where;
+ tmp &= ~mask;
+ tmp |= (symvalue + rela->r_addend) & mask;
+ *where = tmp;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
+
+ case R_TYPE(16_HA):
+ /*
+ * value:6; Field:half16; Expression: #ha(S+A)
+ */
+
+ tmp = symvalue + rela->r_addend;
+ *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: 16_HA %p @ %p in %s\n",
+ (void *)*(where), where, rtems_rtl_obj_oname (obj));
+ break;
+
+ case R_TYPE(16_HI):
+ /*
+ * value:5; Field:half16; Expression: #hi(S+A)
+ */
+ *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: 16_HI %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
+ case R_TYPE(16_LO):
+ /*
+ * value:4; Field:half16; Expression: #lo(S+A)
+ */
+ *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: 16_LO %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
+
+ case R_TYPE(REL14):
+ /*
+ * value:11; Field:low14*; Expression:(S+A-P)>>2
+ */
+ case R_TYPE(REL24):
+ /*
+ * value:10; Field:low24*; Expression:(S+A-P)>>2
+ */
+ if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) {
+ mask = 0x3fffffc;
+ bits = 24;
+ }
+ else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) {
+ mask = 0xfffc;
+ bits = 14;
+ }
+
+ tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
+ if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
+ ((Elf_Sword)tmp < -(1<<(bits-1)))) {
+ printf("Overflow REL14/REL24\n");
+ return false;
+ }
+
+ tmp = *where;
+ tmp &= ~mask;
+ tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
+ *where = tmp;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: REL24/REL14 %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
+
+ case R_TYPE(REL32):
+ /*
+ * value:26; Field:word32*; Expression:S+A-P
+ */
+ *where = symvalue + rela->r_addend - (Elf_Addr)where;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: REL32 %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
+
+ default:
+ printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
+ "contents = %p\n",
+ ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
+ (void *)rela->r_offset, (void *)*where);
+ rtems_rtl_set_error (EINVAL,
+ "%s: Unsupported relocation type %ld "
+ "in non-PLT relocations",
+ sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
+ return false;
+ }
+ return true;
+}
+
+bool
+rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
+ const Elf_Rel* rel,
+ const rtems_rtl_obj_sect_t* sect,
+ const char* symname,
+ const Elf_Byte syminfo,
+ const Elf_Word symvalue)
+{
+ printf ("rtl: rel type record not supported; please report\n");
+ return false;
+}