From a17de72b2546df615a8b548c3a38347920a284e7 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sat, 9 Aug 2014 22:51:26 +0000 Subject: [PATCH] Per discussion on arm@, the compiler generates misaligned relocations. Cope with memcpy when needed. Submitted by: fabient@ (plus changes suggested by thread) --- sys/arm/arm/elf_machdep.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c index 8ef9bd444c93..d8169805d0a1 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);