diff options
Diffstat (limited to 'rts')
-rw-r--r-- | rts/linker/Elf.c | 126 |
1 files changed, 79 insertions, 47 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c index f2fd88f750..fd24a92630 100644 --- a/rts/linker/Elf.c +++ b/rts/linker/Elf.c @@ -1576,8 +1576,11 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, break; case COMPAT_R_X86_64_64: - *(Elf64_Xword *)P = value; + { + Elf64_Xword payload = value; + memcpy((void*)P, &payload, sizeof(payload)); break; + } case COMPAT_R_X86_64_PC32: { @@ -1585,79 +1588,93 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, barf("R_X86_64_PC32 relocation, but ALWAYS_PIC."); #else StgInt64 off = value - P; - if (off >= 0x7fffffffL || off < -0x80000000L) { - if (X86_64_ELF_NONPIC_HACK) { - StgInt64 pltAddress = - (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) - -> jumpIsland; - off = pltAddress + A - P; - } else { - errorBelch("R_X86_64_PC32 relocation out of range: %s = %" - PRId64 "d\nRecompile %s with -fPIC.", - symbol, off, oc->fileName ); - return 0; - } + if (off != (Elf64_Sword)off && X86_64_ELF_NONPIC_HACK) { + StgInt64 pltAddress = + (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + off = pltAddress + A - P; + } + if (off != (Elf64_Sword)off) { + errorBelch( + "R_X86_64_PC32 relocation out of range: %s = %" PRIx64 + "\nRecompile %s with -fPIC -fexternal-dynamic-refs.", + symbol, off, oc->fileName); + return 0; } - *(Elf64_Word *)P = (Elf64_Word)off; + Elf64_Sword payload = off; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; } case COMPAT_R_X86_64_PC64: { - StgInt64 off = value - P; - *(Elf64_Word *)P = (Elf64_Word)off; + Elf64_Sxword payload = value - P; + memcpy((void*)P, &payload, sizeof(payload)); break; } case COMPAT_R_X86_64_32: + { #if defined(ALWAYS_PIC) barf("R_X86_64_32 relocation, but ALWAYS_PIC."); #else - if (value >= 0x7fffffffL) { - if (X86_64_ELF_NONPIC_HACK) { - StgInt64 pltAddress = - (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) - -> jumpIsland; - value = pltAddress + A; - } else { - errorBelch("R_X86_64_32 relocation out of range: %s = %" - PRId64 "d\nRecompile %s with -fPIC.", - symbol, value, oc->fileName ); - return 0; - } + if (value != (Elf64_Word)value && X86_64_ELF_NONPIC_HACK) { + StgInt64 pltAddress = + (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + value = pltAddress + A; + } + if (value != (Elf64_Word)value) { + errorBelch( + "R_X86_64_32 relocation out of range: %s = %" PRIx64 + "\nRecompile %s with -fPIC -fexternal-dynamic-refs.", + symbol, value, oc->fileName); + return 0; } - *(Elf64_Word *)P = (Elf64_Word)value; + Elf64_Word payload = value; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; + } case COMPAT_R_X86_64_32S: + { #if defined(ALWAYS_PIC) barf("R_X86_64_32S relocation, but ALWAYS_PIC."); #else - if ((StgInt64)value > 0x7fffffffL || (StgInt64)value < -0x80000000L) { - if (X86_64_ELF_NONPIC_HACK) { - StgInt64 pltAddress = - (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) - -> jumpIsland; - value = pltAddress + A; - } else { - errorBelch("R_X86_64_32S relocation out of range: %s = %" - PRId64 "d\nRecompile %s with -fPIC.", - symbol, value, oc->fileName ); - return 0; - } + if ((StgInt64)value != (Elf64_Sword)value && X86_64_ELF_NONPIC_HACK) { + StgInt64 pltAddress = + (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + value = pltAddress + A; + } + if ((StgInt64)value != (Elf64_Sword)value) { + errorBelch( + "R_X86_64_32S relocation out of range: %s = %" PRIx64 + "\nRecompile %s with -fPIC -fexternal-dynamic-refs.", + symbol, value, oc->fileName); + return 0; } - *(Elf64_Sword *)P = (Elf64_Sword)value; + Elf64_Sword payload = value; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; + } case COMPAT_R_X86_64_REX_GOTPCRELX: case COMPAT_R_X86_64_GOTPCRELX: case COMPAT_R_X86_64_GOTPCREL: { StgInt64 gotAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)->addr; StgInt64 off = gotAddress + A - P; - *(Elf64_Word *)P = (Elf64_Word)off; + if (off != (Elf64_Sword)off) { + barf( + "COMPAT_R_X86_64_GOTPCREL relocation out of range: " + "%s = %" PRIx64 " in %s.", + symbol, off, oc->fileName); + } + Elf64_Sword payload = off; + memcpy((void*)P, &payload, sizeof(payload)); break; } #if defined(dragonfly_HOST_OS) @@ -1674,7 +1691,15 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, /* make entry in GOT that contains said offset */ StgInt64 gotEntry = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), (S - (Elf64_Addr)(ti.base)))->addr; - *(Elf64_Word *)P = gotEntry + A - P; + StgInt64 off = gotEntry + A - P; + if (off != (Elf64_Sword)off) { + barf( + "COMPAT_R_X86_64_GOTTPOFF relocation out of range: " + "%s = %" PRIx64 " in %s.", + symbol, off, oc->fileName); + } + Elf64_SWord payload = off; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; } @@ -1686,19 +1711,26 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, barf("R_X86_64_PLT32 relocation, but ALWAYS_PIC."); #else StgInt64 off = value - P; - if (off >= 0x7fffffffL || off < -0x80000000L) { + if (off != (Elf64_Sword)off) { StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) -> jumpIsland; off = pltAddress + A - P; } - *(Elf64_Word *)P = (Elf64_Word)off; + if (off != (Elf64_Sword)off) { + barf( + "R_X86_64_PLT32 relocation out of range: " + "%s = %" PRIx64 " in %s.", + symbol, off, oc->fileName); + } + Elf64_Sword payload = off; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; } #endif default: - errorBelch("%s: unhandled ELF relocation(RelA) type %" FMT_Word "\n", + barf("%s: unhandled ELF relocation(RelA) type %" FMT_Word "\n", oc->fileName, (W_)ELF_R_TYPE(info)); return 0; } |