diff options
author | imp <imp@FreeBSD.org> | 2014-08-09 22:51:26 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2014-08-09 22:51:26 +0000 |
commit | dbdd970a0a87a70c1b979be5920dc376378a860f (patch) | |
tree | 3409fab438fda1ca381a82f239472147b6cba804 /sys/arm | |
parent | a1e149db26ec0e4af024b778d9344eebd0f79ff2 (diff) | |
download | FreeBSD-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.c | 38 |
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); |