From da99df366d04cafb044d8fc2c56155017b24c3a8 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 30 Mar 2016 12:40:38 +0000 Subject: [PATCH] Fix handling of addends on i386. Because of merge sections it is not sufficient to just add them while applying a relocation. llvm-svn: 264863 --- lld/ELF/InputSection.cpp | 2 ++ lld/ELF/Target.cpp | 30 +++++++++++++++++++----- lld/ELF/Target.h | 1 + lld/test/ELF/i386-merge.s | 49 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 lld/test/ELF/i386-merge.s diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index d79aad8f865a..119367a3691b 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -274,6 +274,8 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd, continue; } + if (!RelTy::IsRela) + A += Target->getImplicitAddend(BufLoc, Type); uintX_t SymVA = Body.getVA(A); if (Config->EMachine == EM_MIPS) A += findMipsPairedAddend(Buf, BufLoc, Body, &RI, Rels.end()); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 0c9f7042ecc0..11a62c0af232 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -39,7 +39,6 @@ template static void add32(void *P, int32_t V) { write32(P, read32(P) + V); } -static void add32le(uint8_t *P, int32_t V) { add32(P, V); } static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } template static void checkInt(int64_t V, uint32_t Type) { @@ -74,6 +73,7 @@ namespace { class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); + uint64_t getImplicitAddend(uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; uint32_t getTlsGotRel(uint32_t Type) const override; @@ -241,6 +241,10 @@ TargetInfo *createTarget() { TargetInfo::~TargetInfo() {} +uint64_t TargetInfo::getImplicitAddend(uint8_t *Buf, uint32_t Type) const { + return 0; +} + bool TargetInfo::canRelaxTls(uint32_t Type, const SymbolBody *S) const { if (Config->Shared || (S && !S->IsTls)) return false; @@ -509,28 +513,42 @@ bool X86TargetInfo::refersToGotEntry(uint32_t Type) const { return Type == R_386_GOT32; } +uint64_t X86TargetInfo::getImplicitAddend(uint8_t *Buf, uint32_t Type) const { + switch (Type) { + default: + return 0; + case R_386_32: + case R_386_GOT32: + case R_386_GOTOFF: + case R_386_GOTPC: + case R_386_PC32: + case R_386_PLT32: + return read32le(Buf); + } +} + void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA) const { switch (Type) { case R_386_32: - add32le(Loc, SA); + write32le(Loc, SA); break; case R_386_GOT32: { uint64_t V = SA - Out::Got->getVA() - Out::Got->getNumEntries() * 4; checkInt<32>(V, Type); - add32le(Loc, V); + write32le(Loc, V); break; } case R_386_GOTOFF: - add32le(Loc, SA - Out::Got->getVA()); + write32le(Loc, SA - Out::Got->getVA()); break; case R_386_GOTPC: - add32le(Loc, SA + Out::Got->getVA() - P); + write32le(Loc, SA + Out::Got->getVA() - P); break; case R_386_PC32: case R_386_PLT32: - add32le(Loc, SA - P); + write32le(Loc, SA - P); break; case R_386_TLS_GD: case R_386_TLS_LDM: diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 03b06dfa6b56..75b1f60e3bdd 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -31,6 +31,7 @@ public: virtual void writeGotHeader(uint8_t *Buf) const {} virtual void writeGotPltHeader(uint8_t *Buf) const {} virtual void writeGotPlt(uint8_t *Buf, uint64_t Plt) const {}; + virtual uint64_t getImplicitAddend(uint8_t *Buf, uint32_t Type) const; // If lazy binding is supported, the first entry of the PLT has code // to call the dynamic linker to resolve PLT entries the first time diff --git a/lld/test/ELF/i386-merge.s b/lld/test/ELF/i386-merge.s new file mode 100644 index 000000000000..6255a9d8c9c4 --- /dev/null +++ b/lld/test/ELF/i386-merge.s @@ -0,0 +1,49 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t -shared +// RUN: llvm-readobj -s -section-data %t | FileCheck %s + +// CHECK: Name: .mysec +// CHECK-NEXT: Type: +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_MERGE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x114 +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: +// CHECK-NEXT: Info: +// CHECK-NEXT: AddressAlignment: +// CHECK-NEXT: EntrySize: +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 42000000 | +// CHECK-NEXT: ) + + +// CHECK: Name: .text +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_EXECINSTR +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x1000 +// CHECK-NEXT: Offset: 0x1000 +// CHECK-NEXT: Size: 4 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 4 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 14010000 | +// CHECK-NEXT: ) + +// The content of .text should be the address of .mysec. 14010000 is 0x114 in +// little endian. + + .long .mysec+4 + + .section .mysec,"aM",@progbits,4 + .align 4 + .long 0x42 + .long 0x42