summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2014-08-09 22:51:26 +0000
committerimp <imp@FreeBSD.org>2014-08-09 22:51:26 +0000
commitdbdd970a0a87a70c1b979be5920dc376378a860f (patch)
tree3409fab438fda1ca381a82f239472147b6cba804 /sys/arm
parenta1e149db26ec0e4af024b778d9344eebd0f79ff2 (diff)
downloadFreeBSD-src-dbdd970a0a87a70c1b979be5920dc376378a860f.zip
FreeBSD-src-dbdd970a0a87a70c1b979be5920dc376378a860f.tar.gz
Per discussion on arm@, the compiler generates misaligned
relocations. Cope with memcpy when needed. Submitted by: fabient@ (plus changes suggested by thread)
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/elf_machdep.c38
1 files changed, 33 insertions, 5 deletions
diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c
index 8ef9bd4..d816980 100644
--- a/sys/arm/arm/elf_machdep.c
+++ b/sys/arm/arm/elf_machdep.c
@@ -120,6 +120,34 @@ elf32_dump_thread(struct thread *td __unused, void *dst __unused,
{
}
+/*
+ * It is possible for the compiler to emit relocations for unaligned data.
+ * We handle this situation with these inlines.
+ */
+#define RELOC_ALIGNED_P(x) \
+ (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
+
+static __inline Elf_Addr
+load_ptr(Elf_Addr *where)
+{
+ Elf_Addr res;
+
+ if (RELOC_ALIGNED_P(where))
+ return *where;
+ memcpy(&res, where, sizeof(res));
+ return (res);
+}
+
+static __inline void
+store_ptr(Elf_Addr *where, Elf_Addr val)
+{
+ if (RELOC_ALIGNED_P(where))
+ *where = val;
+ else
+ memcpy(where, &val, sizeof(val));
+}
+#undef RELOC_ALIGNED_P
+
/* Process one elf relocation with addend. */
static int
@@ -137,7 +165,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
case ELF_RELOC_REL:
rel = (const Elf_Rel *)data;
where = (Elf_Addr *) (relocbase + rel->r_offset);
- addend = *where;
+ addend = load_ptr(where);
rtype = ELF_R_TYPE(rel->r_info);
symidx = ELF_R_SYM(rel->r_info);
break;
@@ -155,8 +183,8 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
if (local) {
if (rtype == R_ARM_RELATIVE) { /* A + B */
addr = elf_relocaddr(lf, relocbase + addend);
- if (*where != addr)
- *where = addr;
+ if (load_ptr(where) != addr)
+ store_ptr(where, addr);
}
return (0);
}
@@ -170,7 +198,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
- *where += addr;
+ store_ptr(where, addr + load_ptr(where));
break;
case R_ARM_COPY: /* none */
@@ -185,7 +213,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
case R_ARM_JUMP_SLOT:
addr = lookup(lf, symidx, 1);
if (addr) {
- *where = addr;
+ store_ptr(where, addr);
return (0);
}
return (-1);
OpenPOWER on IntegriCloud