[lld] r266158 - Change how we apply relocations.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 12 18:40:20 PDT 2016


Author: rafael
Date: Tue Apr 12 20:40:19 2016
New Revision: 266158

URL: http://llvm.org/viewvc/llvm-project?rev=266158&view=rev
Log:
Change how we apply relocations.

With this patch we use the first scan over the relocations to remember
the information we found about them: will them be relaxed, will a plt be
used, etc.

With that the actual relocation application becomes much simpler. That
is particularly true for the interfaces in Target.h.

This unfortunately means that we now do two passes over relocations for
non SHF_ALLOC sections. I think this can be solved by factoring out the
code that scans a single relocation. It can then be used both as a scan
that record info and for a dedicated direct relocation of non SHF_ALLOC
sections.

I also think it is possible to reduce the number of enum values by
representing a target with just an OutputSection and an offset (which
can be from the start or end).

This should unblock adding features like relocation optimizations.

Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/tls-opt.s

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Apr 12 20:40:19 2016
@@ -147,183 +147,132 @@ void InputSection<ELFT>::copyRelocations
   }
 }
 
-template <class RelTy>
-static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
-  switch (Rel->getType(Config->Mips64EL)) {
-  case R_MIPS_HI16:
-    return R_MIPS_LO16;
-  case R_MIPS_GOT16:
-    return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
-  case R_MIPS_PCHI16:
-    return R_MIPS_PCLO16;
-  case R_MICROMIPS_HI16:
-    return R_MICROMIPS_LO16;
-  default:
-    return R_MIPS_NONE;
-  }
-}
-
-template <endianness E> static int16_t readSignedLo16(uint8_t *Loc) {
-  return read32<E>(Loc) & 0xffff;
+// Page(Expr) is the page address of the expression Expr, defined
+// as (Expr & ~0xFFF). (This applies even if the machine page size
+// supported by the platform has a different value.)
+static uint64_t getAArch64Page(uint64_t Expr) {
+  return Expr & (~static_cast<uint64_t>(0xFFF));
 }
 
 template <class ELFT>
-template <class RelTy>
-int32_t
-InputSectionBase<ELFT>::findMipsPairedAddend(uint8_t *Buf, uint8_t *BufLoc,
-                                             SymbolBody &Sym, const RelTy *Rel,
-                                             const RelTy *End) {
-  uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
-  uint32_t Type = getMipsPairType(Rel, Sym);
-
-  // Some MIPS relocations use addend calculated from addend of the relocation
-  // itself and addend of paired relocation. ABI requires to compute such
-  // combined addend in case of REL relocation record format only.
-  // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-  if (RelTy::IsRela || Type == R_MIPS_NONE)
-    return 0;
-
-  for (const RelTy *RI = Rel; RI != End; ++RI) {
-    if (RI->getType(Config->Mips64EL) != Type)
-      continue;
-    if (RI->getSymbol(Config->Mips64EL) != SymIndex)
-      continue;
-    uintX_t Offset = getOffset(RI->r_offset);
-    if (Offset == (uintX_t)-1)
-      break;
-    const endianness E = ELFT::TargetEndianness;
-    return ((read32<E>(BufLoc) & 0xffff) << 16) +
-           readSignedLo16<E>(Buf + Offset);
-  }
-  unsigned OldType = Rel->getType(Config->Mips64EL);
-  StringRef OldName = getELFRelocationTypeName(Config->EMachine, OldType);
-  StringRef NewName = getELFRelocationTypeName(Config->EMachine, Type);
-  warning("can't find matching " + NewName + " relocation for " + OldName);
-  return 0;
-}
-
-template <class ELFT, class uintX_t>
-static uintX_t adjustMipsSymVA(uint32_t Type, const elf::ObjectFile<ELFT> &File,
-                               const SymbolBody &Body, uintX_t AddrLoc,
-                               uintX_t SymVA) {
-  if (Type == R_MIPS_HI16 && &Body == ElfSym<ELFT>::MipsGpDisp)
-    return SymVA - AddrLoc;
-  if (Type == R_MIPS_LO16 && &Body == ElfSym<ELFT>::MipsGpDisp)
-    return SymVA - AddrLoc + 4;
-  if (Body.isLocal() && (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
+static typename ELFT::uint
+getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
+         const SymbolBody &Body, uint8_t *BufLoc,
+         const elf::ObjectFile<ELFT> &File, RelExpr Expr) {
+  switch (Expr) {
+  case R_TLSLD:
+    return Out<ELFT>::Got->getTlsIndexVA() + A;
+  case R_TLSLD_PC:
+    return Out<ELFT>::Got->getTlsIndexVA() + A - P;
+  case R_THUNK:
+    return Body.getThunkVA<ELFT>();
+  case R_PPC_TOC:
+    return getPPC64TocBase() + A;
+  case R_TLSGD:
+    return Out<ELFT>::Got->getGlobalDynAddr(Body) + A;
+  case R_TLSGD_PC:
+    return Out<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+  case R_PLT:
+    return Body.getPltVA<ELFT>() + A;
+  case R_PLT_PC:
+  case R_PPC_PLT_OPD:
+    return Body.getPltVA<ELFT>() + A - P;
+  case R_SIZE:
+    return Body.getSize<ELFT>() + A;
+  case R_GOT:
+  case R_RELAX_TLS_GD_TO_IE:
+    return Body.getGotVA<ELFT>() + A;
+  case R_GOT_PAGE_PC:
+    return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
+  case R_GOT_PC:
+  case R_RELAX_TLS_GD_TO_IE_PC:
+    return Body.getGotVA<ELFT>() + A - P;
+  case R_ABS:
+  case R_RELAX_TLS_GD_TO_LE:
+  case R_RELAX_TLS_IE_TO_LE:
+  case R_RELAX_TLS_LD_TO_LE:
+    return Body.getVA<ELFT>(A);
+  case R_MIPS_GP0:
     // We need to adjust SymVA value in case of R_MIPS_GPREL16/32
     // relocations because they use the following expression to calculate
     // the relocation's result for local symbol: S + A + GP0 - G.
-    return SymVA + File.getMipsGp0();
-  return SymVA;
-}
-
-template <class ELFT, class uintX_t>
-static uintX_t getMipsGotVA(const SymbolBody &Body, uintX_t SymVA,
-                            uint8_t *BufLoc) {
-  if (Body.isLocal())
+    return Body.getVA<ELFT>(A) + File.getMipsGp0();
+  case R_MIPS_GOT_LOCAL:
     // If relocation against MIPS local symbol requires GOT entry, this entry
     // should be initialized by 'page address'. This address is high 16-bits
     // of sum the symbol's value and the addend.
-    return Out<ELFT>::Got->getMipsLocalPageAddr(SymVA);
-  if (!Body.isPreemptible())
+    return Out<ELFT>::Got->getMipsLocalPageAddr(Body.getVA<ELFT>(A));
+  case R_MIPS_GOT:
     // For non-local symbols GOT entries should contain their full
     // addresses. But if such symbol cannot be preempted, we do not
     // have to put them into the "global" part of GOT and use dynamic
     // linker to determine their actual addresses. That is why we
     // create GOT entries for them in the "local" part of GOT.
-    return Out<ELFT>::Got->getMipsLocalFullAddr(Body);
-  return Body.getGotVA<ELFT>();
+    return Out<ELFT>::Got->getMipsLocalEntryAddr(Body.getVA<ELFT>(A));
+  case R_PPC_OPD: {
+    uint64_t SymVA = Body.getVA<ELFT>(A);
+    // If we have an undefined weak symbol, we might get here with a symbol
+    // address of zero. That could overflow, but the code must be unreachable,
+    // so don't bother doing anything at all.
+    if (!SymVA)
+      return 0;
+    if (Out<ELF64BE>::Opd) {
+      // If this is a local call, and we currently have the address of a
+      // function-descriptor, get the underlying code address instead.
+      uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
+      uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
+      bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
+      if (InOpd)
+        SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
+    }
+    return SymVA - P;
+  }
+  case R_PC:
+    return Body.getVA<ELFT>(A) - P;
+  case R_PAGE_PC:
+    return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
+  }
+  llvm_unreachable("Invalid expression");
 }
 
 template <class ELFT>
-template <class RelTy>
-void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
-                                      ArrayRef<RelTy> Rels) {
-  size_t Num = Rels.end() - Rels.begin();
-  for (size_t I = 0; I < Num; ++I) {
-    const RelTy &RI = *(Rels.begin() + I);
-    uintX_t Offset = getOffset(RI.r_offset);
-    if (Offset == (uintX_t)-1)
-      continue;
-
-    uintX_t A = getAddend<ELFT>(RI);
-    uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
-    uint32_t Type = RI.getType(Config->Mips64EL);
+void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+  const unsigned Bits = sizeof(uintX_t) * 8;
+  for (const Relocation &Rel : Relocations) {
+    uintX_t Offset = Rel.Offset;
     uint8_t *BufLoc = Buf + Offset;
+    uint32_t Type = Rel.Type;
+    uintX_t A = Rel.Addend;
+
     uintX_t AddrLoc = OutSec->getVA() + Offset;
+    RelExpr Expr = Rel.Expr;
+    uint64_t SymVA = SignExtend64<Bits>(
+        getSymVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, BufLoc, *File, Expr));
 
-    if (Target->pointsToLocalDynamicGotEntry(Type) &&
-        !Target->canRelaxTls(Type, nullptr)) {
-      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
-                          Out<ELFT>::Got->getTlsIndexVA() + A);
+    if (Expr == R_RELAX_TLS_IE_TO_LE) {
+      Target->relaxTlsIeToLe(BufLoc, Type, SymVA);
       continue;
     }
-
-    SymbolBody &Body = File->getSymbolBody(SymIndex).repl();
-
-    if (Target->canRelaxTls(Type, &Body)) {
-      uintX_t SymVA;
-      if (Target->needsGot(Type, Body))
-        SymVA = Body.getGotVA<ELFT>();
-      else
-        SymVA = Body.getVA<ELFT>();
-      // By optimizing TLS relocations, it is sometimes needed to skip
-      // relocations that immediately follow TLS relocations. This function
-      // knows how many slots we need to skip.
-      I += Target->relaxTls(BufLoc, BufEnd, Type, AddrLoc, SymVA, Body);
+    if (Expr == R_RELAX_TLS_LD_TO_LE) {
+      Target->relaxTlsLdToLe(BufLoc, Type, SymVA);
       continue;
     }
-
-    // PPC64 has a special relocation representing the TOC base pointer
-    // that does not have a corresponding symbol.
-    if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
-      uintX_t SymVA = getPPC64TocBase() + A;
-      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
+    if (Expr == R_RELAX_TLS_GD_TO_LE) {
+      Target->relaxTlsGdToLe(BufLoc, Type, SymVA);
       continue;
     }
-
-    if (Target->isTlsGlobalDynamicRel(Type) &&
-        !Target->canRelaxTls(Type, &Body)) {
-      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
-                          Out<ELFT>::Got->getGlobalDynAddr(Body) + A);
+    if (Expr == R_RELAX_TLS_GD_TO_IE_PC || Expr == R_RELAX_TLS_GD_TO_IE) {
+      Target->relaxTlsGdToIe(BufLoc, Type, SymVA);
       continue;
     }
 
-    if (!RelTy::IsRela)
-      A += Target->getImplicitAddend(BufLoc, Type);
-    if (Config->EMachine == EM_MIPS)
-      A += findMipsPairedAddend(Buf, BufLoc, Body, &RI, Rels.end());
-    uintX_t SymVA = Body.getVA<ELFT>(A);
-
-    if (Target->needsPlt(Type, Body)) {
-      SymVA = Body.getPltVA<ELFT>() + A;
-    } else if (Target->needsGot(Type, Body)) {
-      if (Config->EMachine == EM_MIPS)
-        SymVA = getMipsGotVA<ELFT>(Body, SymVA, BufLoc);
-      else
-        SymVA = Body.getGotVA<ELFT>() + A;
-      if (Body.isTls())
-        Type = Target->getTlsGotRel(Type);
-    } else if (Target->isSizeRel(Type) && Body.isPreemptible()) {
-      // A SIZE relocation is supposed to set a symbol size, but if a symbol
-      // can be preempted, the size at runtime may be different than link time.
-      // If that's the case, we leave the field alone rather than filling it
-      // with a possibly incorrect value.
-      continue;
-    } else if (Target->needsThunk(Type, *this->getFile(), Body)) {
-      // Get address of a thunk code related to the symbol.
-      SymVA = Body.getThunkVA<ELFT>();
-    } else if (!Target->needsCopyRel<ELFT>(Type, Body) &&
-               Body.isPreemptible()) {
-      continue;
-    } else if (Config->EMachine == EM_MIPS) {
-      SymVA = adjustMipsSymVA<ELFT>(Type, *File, Body, AddrLoc, SymVA);
+    if (Expr == R_PPC_PLT_OPD) {
+      uint32_t Nop = 0x60000000;
+      if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == Nop)
+        write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
     }
-    if (Target->isSizeRel(Type))
-      SymVA = Body.getSize<ELFT>() + A;
 
-    Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
+    Target->relocateOne(BufLoc, Type, SymVA);
   }
 }
 
@@ -348,12 +297,7 @@ template <class ELFT> void InputSection<
 
   // Iterate over all relocation sections that apply to this section.
   uint8_t *BufEnd = Buf + OutSecOff + Data.size();
-  for (const Elf_Shdr *RelSec : this->RelocSections) {
-    if (RelSec->sh_type == SHT_RELA)
-      this->relocate(Buf, BufEnd, EObj.relas(RelSec));
-    else
-      this->relocate(Buf, BufEnd, EObj.rels(RelSec));
-  }
+  this->relocate(Buf, BufEnd);
 
   // The section might have a data/code generated by the linker and need
   // to be written after the section. Usually these are thunks - small piece

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Tue Apr 12 20:40:19 2016
@@ -24,6 +24,42 @@ template <class ELFT> class ObjectFile;
 template <class ELFT> class OutputSection;
 template <class ELFT> class OutputSectionBase;
 
+enum RelExpr {
+  R_ABS,
+  R_GOT,
+  R_GOT_PAGE_PC,
+  R_GOT_PC,
+  R_MIPS_GOT,
+  R_MIPS_GOT_LOCAL,
+  R_MIPS_GP0,
+  R_PAGE_PC,
+  R_PC,
+  R_PLT,
+  R_PLT_PC,
+  R_PPC_OPD,
+  R_PPC_PLT_OPD,
+  R_PPC_TOC,
+  R_RELAX_TLS_GD_TO_IE,
+  R_RELAX_TLS_GD_TO_IE_PC,
+  R_RELAX_TLS_GD_TO_LE,
+  R_RELAX_TLS_IE_TO_LE,
+  R_RELAX_TLS_LD_TO_LE,
+  R_SIZE,
+  R_THUNK,
+  R_TLSGD,
+  R_TLSGD_PC,
+  R_TLSLD,
+  R_TLSLD_PC
+};
+
+struct Relocation {
+  RelExpr Expr;
+  uint32_t Type;
+  uint64_t Offset;
+  uint64_t Addend;
+  SymbolBody *Sym;
+};
+
 // This corresponds to a section of an input file.
 template <class ELFT> class InputSectionBase {
 protected:
@@ -78,13 +114,8 @@ public:
   InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel) const;
   InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel) const;
 
-  template <class RelTy>
-  void relocate(uint8_t *Buf, uint8_t *BufEnd, llvm::ArrayRef<RelTy> Rels);
-
-private:
-  template <class RelTy>
-  int32_t findMipsPairedAddend(uint8_t *Buf, uint8_t *BufLoc, SymbolBody &Sym,
-                               const RelTy *Rel, const RelTy *End);
+  void relocate(uint8_t *Buf, uint8_t *BufEnd);
+  std::vector<Relocation> Relocations;
 };
 
 template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Tue Apr 12 20:40:19 2016
@@ -166,12 +166,6 @@ template <class ELFT> bool GotSection<EL
 
 template <class ELFT>
 typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getMipsLocalFullAddr(const SymbolBody &B) {
-  return getMipsLocalEntryAddr(B.getVA<ELFT>());
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
 GotSection<ELFT>::getMipsLocalPageAddr(uintX_t EntryValue) {
   // Initialize the entry by the %hi(EntryValue) expression
   // but without right-shifting.
@@ -1211,16 +1205,8 @@ template <class ELFT> void EHOutputSecti
     }
   }
 
-  for (EHInputSection<ELFT> *S : Sections) {
-    const Elf_Shdr *RelSec = S->RelocSection;
-    if (!RelSec)
-      continue;
-    ELFFile<ELFT> &EObj = S->getFile()->getObj();
-    if (RelSec->sh_type == SHT_RELA)
-      S->relocate(Buf, nullptr, EObj.relas(RelSec));
-    else
-      S->relocate(Buf, nullptr, EObj.rels(RelSec));
-  }
+  for (EHInputSection<ELFT> *S : Sections)
+    S->relocate(Buf, nullptr);
 }
 
 template <class ELFT>

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Tue Apr 12 20:40:19 2016
@@ -112,7 +112,7 @@ public:
   bool addDynTlsEntry(SymbolBody &Sym);
   bool addTlsIndex();
   bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); }
-  uintX_t getMipsLocalFullAddr(const SymbolBody &B);
+  uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
   uintX_t getMipsLocalPageAddr(uintX_t Addr);
   uintX_t getGlobalDynAddr(const SymbolBody &B) const;
   uintX_t getGlobalDynOffset(const SymbolBody &B) const;
@@ -139,7 +139,6 @@ private:
   llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
   llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
 
-  uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
 };
 
 template <class ELFT>

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Tue Apr 12 20:40:19 2016
@@ -11,7 +11,7 @@
 // GOT or PLT entries, etc., are handled in this file.
 //
 // Refer the ELF spec for the single letter varaibles, S, A or P, used
-// in this file. SA is S+A.
+// in this file.
 //
 //===----------------------------------------------------------------------===//
 
@@ -70,6 +70,7 @@ namespace {
 class X86TargetInfo final : public TargetInfo {
 public:
   X86TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
   uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
   void writeGotPltHeader(uint8_t *Buf) const override;
   uint32_t getDynRel(uint32_t Type) const override;
@@ -87,17 +88,12 @@ public:
   bool needsDynRelative(uint32_t Type) const override;
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool needsPltImpl(uint32_t Type) const override;
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
 
-  size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
+  void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
 
   bool isGotRelative(uint32_t Type) const override;
   bool refersToGotEntry(uint32_t Type) const override;
@@ -106,6 +102,7 @@ public:
 class X86_64TargetInfo final : public TargetInfo {
 public:
   X86_64TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
   uint32_t getDynRel(uint32_t Type) const override;
   uint32_t getTlsGotRel(uint32_t Type) const override;
   bool pointsToLocalDynamicGotEntry(uint32_t Type) const override;
@@ -121,44 +118,40 @@ public:
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool refersToGotEntry(uint32_t Type) const override;
   bool needsPltImpl(uint32_t Type) const override;
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
   bool isRelRelative(uint32_t Type) const override;
   bool isSizeRel(uint32_t Type) const override;
 
-  size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
+  void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
 };
 
 class PPCTargetInfo final : public TargetInfo {
 public:
   PPCTargetInfo();
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
   bool isRelRelative(uint32_t Type) const override;
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
 };
 
 class PPC64TargetInfo final : public TargetInfo {
 public:
   PPC64TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
   void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
                 int32_t Index, unsigned RelOff) const override;
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool needsPltImpl(uint32_t Type) const override;
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
   bool isRelRelative(uint32_t Type) const override;
 };
 
 class AArch64TargetInfo final : public TargetInfo {
 public:
   AArch64TargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
   uint32_t getDynRel(uint32_t Type) const override;
   bool isTlsGlobalDynamicRel(uint32_t Type) const override;
   bool isTlsInitialExecRel(uint32_t Type) const override;
@@ -172,12 +165,9 @@ public:
   bool needsGot(uint32_t Type, const SymbolBody &S) const override;
   bool refersToGotEntry(uint32_t Type) const override;
   bool needsPltImpl(uint32_t Type) const override;
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
-  size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
-  size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                        uint64_t P, uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
 
 private:
   static const uint64_t TcbSize = 16;
@@ -186,13 +176,14 @@ private:
 class AMDGPUTargetInfo final : public TargetInfo {
 public:
   AMDGPUTargetInfo() {}
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
 };
 
 template <class ELFT> class MipsTargetInfo final : public TargetInfo {
 public:
   MipsTargetInfo();
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
   uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
   uint32_t getDynRel(uint32_t Type) const override;
   void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
@@ -206,8 +197,7 @@ public:
   bool needsPltImpl(uint32_t Type) const override;
   bool needsThunk(uint32_t Type, const InputFile &File,
                   const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
   bool isHintRel(uint32_t Type) const override;
   bool isRelRelative(uint32_t Type) const override;
   bool refersToGotEntry(uint32_t Type) const override;
@@ -354,37 +344,23 @@ bool TargetInfo::isTlsGlobalDynamicRel(u
   return false;
 }
 
-size_t TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                            uint64_t P, uint64_t SA,
-                            const SymbolBody &S) const {
-  if (isTlsGlobalDynamicRel(Type)) {
-    if (S.isPreemptible())
-      return relaxTlsGdToIe(Loc, BufEnd, Type, P, SA);
-    return relaxTlsGdToLe(Loc, BufEnd, Type, P, SA);
-  }
-  if (isTlsLocalDynamicRel(Type))
-    return relaxTlsLdToLe(Loc, BufEnd, Type, P, SA);
-  assert(isTlsInitialExecRel(Type));
-  return relaxTlsIeToLe(Loc, BufEnd, Type, P, SA);
-}
-
-size_t TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                  uint64_t P, uint64_t SA) const {
+void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
   llvm_unreachable("Should not have claimed to be relaxable");
 }
 
-size_t TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                  uint64_t P, uint64_t SA) const {
+void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
   llvm_unreachable("Should not have claimed to be relaxable");
 }
 
-size_t TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                  uint64_t P, uint64_t SA) const {
+void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
   llvm_unreachable("Should not have claimed to be relaxable");
 }
 
-size_t TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                  uint64_t P, uint64_t SA) const {
+void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
   llvm_unreachable("Should not have claimed to be relaxable");
 }
 
@@ -400,6 +376,18 @@ X86TargetInfo::X86TargetInfo() {
   UseLazyBinding = true;
   PltEntrySize = 16;
   PltZeroSize = 16;
+  TlsGdToLeSkip = 2;
+}
+
+RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_386_PLT32:
+  case R_386_PC32:
+  case R_386_GOTPC:
+    return R_PC;
+  }
 }
 
 bool X86TargetInfo::isRelRelative(uint32_t Type) const {
@@ -538,33 +526,33 @@ uint64_t X86TargetInfo::getImplicitAdden
   }
 }
 
-void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const {
+void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
   switch (Type) {
   case R_386_32:
-    write32le(Loc, SA);
+    write32le(Loc, Val);
     break;
   case R_386_GOT32: {
-    uint64_t V = SA - Out<ELF32LE>::Got->getVA() -
+    uint64_t V = Val - Out<ELF32LE>::Got->getVA() -
                  Out<ELF32LE>::Got->getNumEntries() * 4;
     checkInt<32>(V, Type);
     write32le(Loc, V);
     break;
   }
   case R_386_GOTOFF:
-    write32le(Loc, SA - Out<ELF32LE>::Got->getVA());
+    write32le(Loc, Val - Out<ELF32LE>::Got->getVA());
     break;
   case R_386_GOTPC:
-    write32le(Loc, SA + Out<ELF32LE>::Got->getVA() - P);
+    write32le(Loc, Val + Out<ELF32LE>::Got->getVA());
     break;
   case R_386_PC32:
   case R_386_PLT32:
-    write32le(Loc, SA - P);
+    write32le(Loc, Val);
     break;
   case R_386_TLS_GD:
   case R_386_TLS_LDM:
   case R_386_TLS_TPOFF: {
-    uint64_t V = SA - Out<ELF32LE>::Got->getVA() -
+    uint64_t V = Val - Out<ELF32LE>::Got->getVA() -
                  Out<ELF32LE>::Got->getNumEntries() * 4;
     checkInt<32>(V, Type);
     write32le(Loc, V);
@@ -572,13 +560,13 @@ void X86TargetInfo::relocateOne(uint8_t
   }
   case R_386_TLS_IE:
   case R_386_TLS_LDO_32:
-    write32le(Loc, SA);
+    write32le(Loc, Val);
     break;
   case R_386_TLS_LE:
-    write32le(Loc, SA - Out<ELF32LE>::TlsPhdr->p_memsz);
+    write32le(Loc, Val - Out<ELF32LE>::TlsPhdr->p_memsz);
     break;
   case R_386_TLS_LE_32:
-    write32le(Loc, Out<ELF32LE>::TlsPhdr->p_memsz - SA);
+    write32le(Loc, Out<ELF32LE>::TlsPhdr->p_memsz - Val);
     break;
   default:
     fatal("unrecognized reloc " + Twine(Type));
@@ -589,9 +577,8 @@ bool X86TargetInfo::needsDynRelative(uin
   return Config->Shared && Type == R_386_TLS_IE;
 }
 
-size_t X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                     uint32_t Type, uint64_t P,
-                                     uint64_t SA) const {
+void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
   // GD can be optimized to LE:
   //   leal x at tlsgd(, %ebx, 1),
   //   call __tls_get_addr at plt
@@ -606,11 +593,7 @@ size_t X86TargetInfo::relaxTlsGdToLe(uin
       0x81, 0xe8, 0x00, 0x00, 0x00, 0x00  // subl 0(%ebx), %eax
   };
   memcpy(Loc - 3, Inst, sizeof(Inst));
-  relocateOne(Loc + 5, BufEnd, R_386_32, P,
-              Out<ELF32LE>::TlsPhdr->p_memsz - SA);
-
-  // The next relocation should be against __tls_get_addr, so skip it
-  return 1;
+  relocateOne(Loc + 5, R_386_32, Out<ELF32LE>::TlsPhdr->p_memsz - Val);
 }
 
 // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.1
@@ -621,20 +604,15 @@ size_t X86TargetInfo::relaxTlsGdToLe(uin
 // Is converted to:
 //   movl %gs:0, %eax
 //   addl x at gotntpoff(%ebx), %eax
-size_t X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd,
-                                     uint32_t Type, uint64_t P,
-                                     uint64_t SA) const {
+void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
   const uint8_t Inst[] = {
       0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
       0x03, 0x83, 0x00, 0x00, 0x00, 0x00  // addl 0(%ebx), %eax
   };
   memcpy(Loc - 3, Inst, sizeof(Inst));
-  relocateOne(Loc + 5, BufEnd, R_386_32, P,
-              SA - Out<ELF32LE>::Got->getVA() -
-                  Out<ELF32LE>::Got->getNumEntries() * 4);
-
-  // The next relocation should be against __tls_get_addr, so skip it
-  return 1;
+  relocateOne(Loc + 5, R_386_32, Val - Out<ELF32LE>::Got->getVA() -
+                                     Out<ELF32LE>::Got->getNumEntries() * 4);
 }
 
 // In some conditions, relocations can be optimized to avoid using GOT.
@@ -642,10 +620,8 @@ size_t X86TargetInfo::relaxTlsGdToIe(uin
 // Read "ELF Handling For Thread-Local Storage, 5.1
 // IA-32 Linker Optimizations" (http://www.akkadia.org/drepper/tls.pdf)
 // by Ulrich Drepper for details.
-
-size_t X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                     uint32_t Type, uint64_t P,
-                                     uint64_t SA) const {
+void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
   // Ulrich's document section 6.2 says that @gotntpoff can
   // be used with MOVL or ADDL instructions.
   // @indntpoff is similar to @gotntpoff, but for use in
@@ -679,17 +655,14 @@ size_t X86TargetInfo::relaxTlsIeToLe(uin
     else
       *Op = 0x80 | Reg | (Reg << 3);
   }
-  relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA);
-
-  return 0;
+  relocateOne(Loc, R_386_TLS_LE, Val);
 }
 
-size_t X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                     uint32_t Type, uint64_t P,
-                                     uint64_t SA) const {
+void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
   if (Type == R_386_TLS_LDO_32) {
-    relocateOne(Loc, BufEnd, R_386_TLS_LE, P, SA);
-    return 0;
+    relocateOne(Loc, R_386_TLS_LE, Val);
+    return;
   }
 
   // LD can be optimized to LE:
@@ -705,9 +678,6 @@ size_t X86TargetInfo::relaxTlsLdToLe(uin
       0x8d, 0x74, 0x26, 0x00              // leal 0(%esi,1),%esi
   };
   memcpy(Loc - 2, Inst, sizeof(Inst));
-
-  // The next relocation should be against __tls_get_addr, so skip it
-  return 1;
 }
 
 X86_64TargetInfo::X86_64TargetInfo() {
@@ -722,6 +692,21 @@ X86_64TargetInfo::X86_64TargetInfo() {
   UseLazyBinding = true;
   PltEntrySize = 16;
   PltZeroSize = 16;
+  TlsGdToLeSkip = 2;
+}
+
+RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_X86_64_GOTPCREL:
+  case R_X86_64_PLT32:
+  case R_X86_64_PC32:
+  case R_X86_64_TLSLD:
+  case R_X86_64_GOTTPOFF:
+  case R_X86_64_TLSGD:
+    return R_PC;
+  }
 }
 
 void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
@@ -847,18 +832,14 @@ bool X86_64TargetInfo::isSizeRel(uint32_
 // Is converted to:
 //  mov %fs:0x0,%rax
 //  lea x at tpoff,%rax
-size_t X86_64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                        uint32_t Type, uint64_t P,
-                                        uint64_t SA) const {
+void X86_64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                      uint64_t Val) const {
   const uint8_t Inst[] = {
       0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
       0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00              // lea x at tpoff,%rax
   };
   memcpy(Loc - 4, Inst, sizeof(Inst));
-  relocateOne(Loc + 8, BufEnd, R_X86_64_TPOFF32, P, SA);
-
-  // The next relocation should be against __tls_get_addr, so skip it
-  return 1;
+  relocateOne(Loc + 8, R_X86_64_TPOFF32, Val + 4);
 }
 
 // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
@@ -872,18 +853,14 @@ size_t X86_64TargetInfo::relaxTlsGdToLe(
 // Is converted to:
 //  mov %fs:0x0,%rax
 //  addq x at tpoff,%rax
-size_t X86_64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd,
-                                        uint32_t Type, uint64_t P,
-                                        uint64_t SA) const {
+void X86_64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
+                                      uint64_t Val) const {
   const uint8_t Inst[] = {
       0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax
       0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00              // addq x at tpoff,%rax
   };
   memcpy(Loc - 4, Inst, sizeof(Inst));
-  relocateOne(Loc + 8, BufEnd, R_X86_64_PC32, P + 12, SA);
-
-  // The next relocation should be against __tls_get_addr, so skip it
-  return 1;
+  relocateOne(Loc + 8, R_X86_64_PC32, Val - 8);
 }
 
 // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
@@ -891,9 +868,8 @@ size_t X86_64TargetInfo::relaxTlsGdToIe(
 // This function does that. Read "ELF Handling For Thread-Local Storage,
 // 5.5 x86-x64 linker optimizations" (http://www.akkadia.org/drepper/tls.pdf)
 // by Ulrich Drepper for details.
-size_t X86_64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                        uint32_t Type, uint64_t P,
-                                        uint64_t SA) const {
+void X86_64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                      uint64_t Val) const {
   // Ulrich's document section 6.5 says that @gottpoff(%rip) must be
   // used in MOVQ or ADDQ instructions only.
   // "MOVQ foo at GOTTPOFF(%RIP), %REG" is transformed to "MOVQ $foo, %REG".
@@ -919,8 +895,7 @@ size_t X86_64TargetInfo::relaxTlsIeToLe(
   if (*Prefix == 0x4c)
     *Prefix = (IsMov || RspAdd) ? 0x49 : 0x4d;
   *RegSlot = (IsMov || RspAdd) ? (0xc0 | Reg) : (0x80 | Reg | (Reg << 3));
-  relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA);
-  return 0;
+  relocateOne(Loc, R_X86_64_TPOFF32, Val + 4);
 }
 
 // "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
@@ -934,16 +909,15 @@ size_t X86_64TargetInfo::relaxTlsIeToLe(
 //  .byte 0x66
 //  mov %fs:0,%rax
 //  leaq bar at tpoff(%rax), %rcx
-size_t X86_64TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                        uint32_t Type, uint64_t P,
-                                        uint64_t SA) const {
+void X86_64TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
+                                      uint64_t Val) const {
   if (Type == R_X86_64_DTPOFF64) {
-    write64le(Loc, SA - Out<ELF64LE>::TlsPhdr->p_memsz);
-    return 0;
+    write64le(Loc, Val - Out<ELF64LE>::TlsPhdr->p_memsz);
+    return;
   }
   if (Type == R_X86_64_DTPOFF32) {
-    relocateOne(Loc, BufEnd, R_X86_64_TPOFF32, P, SA);
-    return 0;
+    relocateOne(Loc, R_X86_64_TPOFF32, Val);
+    return;
   }
 
   const uint8_t Inst[] = {
@@ -952,27 +926,25 @@ size_t X86_64TargetInfo::relaxTlsLdToLe(
       0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax
   };
   memcpy(Loc - 3, Inst, sizeof(Inst));
-  // The next relocation should be against __tls_get_addr, so skip it
-  return 1;
 }
 
-void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                   uint64_t P, uint64_t SA) const {
+void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
   switch (Type) {
   case R_X86_64_32:
-    checkUInt<32>(SA, Type);
-    write32le(Loc, SA);
+    checkUInt<32>(Val, Type);
+    write32le(Loc, Val);
     break;
   case R_X86_64_32S:
-    checkInt<32>(SA, Type);
-    write32le(Loc, SA);
+    checkInt<32>(Val, Type);
+    write32le(Loc, Val);
     break;
   case R_X86_64_64:
   case R_X86_64_DTPOFF64:
-    write64le(Loc, SA);
+    write64le(Loc, Val);
     break;
   case R_X86_64_DTPOFF32:
-    write32le(Loc, SA);
+    write32le(Loc, Val);
     break;
   case R_X86_64_GOTPCREL:
   case R_X86_64_GOTPCRELX:
@@ -981,16 +953,16 @@ void X86_64TargetInfo::relocateOne(uint8
   case R_X86_64_PLT32:
   case R_X86_64_TLSGD:
   case R_X86_64_TLSLD:
-    write32le(Loc, SA - P);
+    write32le(Loc, Val);
     break;
   case R_X86_64_SIZE32:
-    write32le(Loc, SA);
+    write32le(Loc, Val);
     break;
   case R_X86_64_SIZE64:
-    write64le(Loc, SA);
+    write64le(Loc, Val);
     break;
   case R_X86_64_TPOFF32: {
-    uint64_t Val = SA - Out<ELF64LE>::TlsPhdr->p_memsz;
+    Val -= Out<ELF64LE>::TlsPhdr->p_memsz;
     checkInt<32>(Val, Type);
     write32le(Loc, Val);
     break;
@@ -1015,20 +987,24 @@ static uint16_t applyPPCHighesta(uint64_
 PPCTargetInfo::PPCTargetInfo() {}
 bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; }
 
-void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const {
+void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                uint64_t Val) const {
   switch (Type) {
   case R_PPC_ADDR16_HA:
-    write16be(Loc, applyPPCHa(SA));
+    write16be(Loc, applyPPCHa(Val));
     break;
   case R_PPC_ADDR16_LO:
-    write16be(Loc, applyPPCLo(SA));
+    write16be(Loc, applyPPCLo(Val));
     break;
   default:
     fatal("unrecognized reloc " + Twine(Type));
   }
 }
 
+RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  return R_ABS;
+}
+
 PPC64TargetInfo::PPC64TargetInfo() {
   GotRel = R_PPC64_GLOB_DAT;
   RelativeRel = R_PPC64_RELATIVE;
@@ -1066,6 +1042,15 @@ uint64_t getPPC64TocBase() {
   return TocVA + 0x8000;
 }
 
+RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_PPC64_REL24:
+    return R_PPC_OPD;
+  }
+}
+
 void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
                                uint64_t PltEntryAddr, int32_t Index,
                                unsigned RelOff) const {
@@ -1118,118 +1103,93 @@ bool PPC64TargetInfo::isRelRelative(uint
   }
 }
 
-void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                  uint64_t P, uint64_t SA) const {
+void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                  uint64_t Val) const {
   uint64_t TB = getPPC64TocBase();
 
   // For a TOC-relative relocation, adjust the addend and proceed in terms of
   // the corresponding ADDR16 relocation type.
   switch (Type) {
-  case R_PPC64_TOC16:       Type = R_PPC64_ADDR16;       SA -= TB; break;
-  case R_PPC64_TOC16_DS:    Type = R_PPC64_ADDR16_DS;    SA -= TB; break;
-  case R_PPC64_TOC16_HA:    Type = R_PPC64_ADDR16_HA;    SA -= TB; break;
-  case R_PPC64_TOC16_HI:    Type = R_PPC64_ADDR16_HI;    SA -= TB; break;
-  case R_PPC64_TOC16_LO:    Type = R_PPC64_ADDR16_LO;    SA -= TB; break;
-  case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; SA -= TB; break;
+  case R_PPC64_TOC16:       Type = R_PPC64_ADDR16;       Val -= TB; break;
+  case R_PPC64_TOC16_DS:    Type = R_PPC64_ADDR16_DS;    Val -= TB; break;
+  case R_PPC64_TOC16_HA:    Type = R_PPC64_ADDR16_HA;    Val -= TB; break;
+  case R_PPC64_TOC16_HI:    Type = R_PPC64_ADDR16_HI;    Val -= TB; break;
+  case R_PPC64_TOC16_LO:    Type = R_PPC64_ADDR16_LO;    Val -= TB; break;
+  case R_PPC64_TOC16_LO_DS: Type = R_PPC64_ADDR16_LO_DS; Val -= TB; break;
   default: break;
   }
 
   switch (Type) {
   case R_PPC64_ADDR14: {
-    checkAlignment<4>(SA, Type);
+    checkAlignment<4>(Val, Type);
     // Preserve the AA/LK bits in the branch instruction
     uint8_t AALK = Loc[3];
-    write16be(Loc + 2, (AALK & 3) | (SA & 0xfffc));
+    write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc));
     break;
   }
   case R_PPC64_ADDR16:
-    checkInt<16>(SA, Type);
-    write16be(Loc, SA);
+    checkInt<16>(Val, Type);
+    write16be(Loc, Val);
     break;
   case R_PPC64_ADDR16_DS:
-    checkInt<16>(SA, Type);
-    write16be(Loc, (read16be(Loc) & 3) | (SA & ~3));
+    checkInt<16>(Val, Type);
+    write16be(Loc, (read16be(Loc) & 3) | (Val & ~3));
     break;
   case R_PPC64_ADDR16_HA:
-    write16be(Loc, applyPPCHa(SA));
+    write16be(Loc, applyPPCHa(Val));
     break;
   case R_PPC64_ADDR16_HI:
-    write16be(Loc, applyPPCHi(SA));
+    write16be(Loc, applyPPCHi(Val));
     break;
   case R_PPC64_ADDR16_HIGHER:
-    write16be(Loc, applyPPCHigher(SA));
+    write16be(Loc, applyPPCHigher(Val));
     break;
   case R_PPC64_ADDR16_HIGHERA:
-    write16be(Loc, applyPPCHighera(SA));
+    write16be(Loc, applyPPCHighera(Val));
     break;
   case R_PPC64_ADDR16_HIGHEST:
-    write16be(Loc, applyPPCHighest(SA));
+    write16be(Loc, applyPPCHighest(Val));
     break;
   case R_PPC64_ADDR16_HIGHESTA:
-    write16be(Loc, applyPPCHighesta(SA));
+    write16be(Loc, applyPPCHighesta(Val));
     break;
   case R_PPC64_ADDR16_LO:
-    write16be(Loc, applyPPCLo(SA));
+    write16be(Loc, applyPPCLo(Val));
     break;
   case R_PPC64_ADDR16_LO_DS:
-    write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(SA) & ~3));
+    write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3));
     break;
   case R_PPC64_ADDR32:
-    checkInt<32>(SA, Type);
-    write32be(Loc, SA);
+    checkInt<32>(Val, Type);
+    write32be(Loc, Val);
     break;
   case R_PPC64_ADDR64:
-    write64be(Loc, SA);
+    write64be(Loc, Val);
     break;
   case R_PPC64_REL16_HA:
-    write16be(Loc, applyPPCHa(SA - P));
+    write16be(Loc, applyPPCHa(Val));
     break;
   case R_PPC64_REL16_HI:
-    write16be(Loc, applyPPCHi(SA - P));
+    write16be(Loc, applyPPCHi(Val));
     break;
   case R_PPC64_REL16_LO:
-    write16be(Loc, applyPPCLo(SA - P));
+    write16be(Loc, applyPPCLo(Val));
     break;
   case R_PPC64_REL24: {
-    // If we have an undefined weak symbol, we might get here with a symbol
-    // address of zero. That could overflow, but the code must be unreachable,
-    // so don't bother doing anything at all.
-    if (!SA)
-      break;
-
-    uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
-    uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
-    bool InPlt = PltStart <= SA && SA < PltEnd;
-
-    if (!InPlt && Out<ELF64BE>::Opd) {
-      // If this is a local call, and we currently have the address of a
-      // function-descriptor, get the underlying code address instead.
-      uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
-      uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
-      bool InOpd = OpdStart <= SA && SA < OpdEnd;
-
-      if (InOpd)
-        SA = read64be(&Out<ELF64BE>::OpdBuf[SA - OpdStart]);
-    }
-
     uint32_t Mask = 0x03FFFFFC;
-    checkInt<24>(SA - P, Type);
-    write32be(Loc, (read32be(Loc) & ~Mask) | ((SA - P) & Mask));
-
-    uint32_t Nop = 0x60000000;
-    if (InPlt && Loc + 8 <= BufEnd && read32be(Loc + 4) == Nop)
-      write32be(Loc + 4, 0xe8410028); // ld %r2, 40(%r1)
+    checkInt<24>(Val, Type);
+    write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask));
     break;
   }
   case R_PPC64_REL32:
-    checkInt<32>(SA - P, Type);
-    write32be(Loc, SA - P);
+    checkInt<32>(Val, Type);
+    write32be(Loc, Val);
     break;
   case R_PPC64_REL64:
-    write64be(Loc, SA - P);
+    write64be(Loc, Val);
     break;
   case R_PPC64_TOC:
-    write64be(Loc, SA);
+    write64be(Loc, Val);
     break;
   default:
     fatal("unrecognized reloc " + Twine(Type));
@@ -1250,6 +1210,27 @@ AArch64TargetInfo::AArch64TargetInfo() {
   PltZeroSize = 32;
 }
 
+RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
+                                      const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_AARCH64_JUMP26:
+  case R_AARCH64_CALL26:
+  case R_AARCH64_PREL16:
+  case R_AARCH64_PREL32:
+  case R_AARCH64_PREL64:
+  case R_AARCH64_CONDBR19:
+  case R_AARCH64_ADR_PREL_LO21:
+  case R_AARCH64_TSTBR14:
+    return R_PC;
+  case R_AARCH64_ADR_GOT_PAGE:
+  case R_AARCH64_ADR_PREL_PG_HI21:
+  case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    return R_PAGE_PC;
+  }
+}
+
 bool AArch64TargetInfo::isRelRelative(uint32_t Type) const {
   switch (Type) {
   default:
@@ -1303,6 +1284,10 @@ void AArch64TargetInfo::writeGotPlt(uint
   write64le(Buf, Out<ELF64LE>::Plt->getVA());
 }
 
+static uint64_t getAArch64Page(uint64_t Expr) {
+  return Expr & (~static_cast<uint64_t>(0xFFF));
+}
+
 void AArch64TargetInfo::writePltZero(uint8_t *Buf) const {
   const uint8_t PltData[] = {
       0xf0, 0x7b, 0xbf, 0xa9, // stp	x16, x30, [sp,#-16]!
@@ -1318,11 +1303,10 @@ void AArch64TargetInfo::writePltZero(uin
 
   uint64_t Got = Out<ELF64LE>::GotPlt->getVA();
   uint64_t Plt = Out<ELF64LE>::Plt->getVA();
-  relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, Plt + 4, Got + 16);
-  relocateOne(Buf + 8, Buf + 12, R_AARCH64_LDST64_ABS_LO12_NC, Plt + 8,
-              Got + 16);
-  relocateOne(Buf + 12, Buf + 16, R_AARCH64_ADD_ABS_LO12_NC, Plt + 12,
-              Got + 16);
+  relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
+              getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
+  relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
+  relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
 }
 
 void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
@@ -1336,12 +1320,10 @@ void AArch64TargetInfo::writePlt(uint8_t
   };
   memcpy(Buf, Inst, sizeof(Inst));
 
-  relocateOne(Buf, Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr,
-              GotEntryAddr);
-  relocateOne(Buf + 4, Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, PltEntryAddr + 4,
-              GotEntryAddr);
-  relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 8,
-              GotEntryAddr);
+  relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
+              getAArch64Page(GotEntryAddr) - getAArch64Page(PltEntryAddr));
+  relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr);
+  relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr);
 }
 
 uint32_t AArch64TargetInfo::getTlsGotRel(uint32_t Type) const {
@@ -1409,112 +1391,104 @@ static inline void updateAArch64Add(uint
   or32le(L, (Imm & 0xFFF) << 10);
 }
 
-// Page(Expr) is the page address of the expression Expr, defined
-// as (Expr & ~0xFFF). (This applies even if the machine page size
-// supported by the platform has a different value.)
-static uint64_t getAArch64Page(uint64_t Expr) {
-  return Expr & (~static_cast<uint64_t>(0xFFF));
-}
-
-void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
-                                    uint32_t Type, uint64_t P,
-                                    uint64_t SA) const {
+void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                    uint64_t Val) const {
   switch (Type) {
   case R_AARCH64_ABS16:
-    checkIntUInt<16>(SA, Type);
-    write16le(Loc, SA);
+    checkIntUInt<16>(Val, Type);
+    write16le(Loc, Val);
     break;
   case R_AARCH64_ABS32:
-    checkIntUInt<32>(SA, Type);
-    write32le(Loc, SA);
+    checkIntUInt<32>(Val, Type);
+    write32le(Loc, Val);
     break;
   case R_AARCH64_ABS64:
-    write64le(Loc, SA);
+    write64le(Loc, Val);
     break;
   case R_AARCH64_ADD_ABS_LO12_NC:
     // This relocation stores 12 bits and there's no instruction
     // to do it. Instead, we do a 32 bits store of the value
     // of r_addend bitwise-or'ed Loc. This assumes that the addend
     // bits in Loc are zero.
-    or32le(Loc, (SA & 0xFFF) << 10);
+    or32le(Loc, (Val & 0xFFF) << 10);
     break;
   case R_AARCH64_ADR_GOT_PAGE: {
-    uint64_t X = getAArch64Page(SA) - getAArch64Page(P);
+    uint64_t X = Val;
     checkInt<33>(X, Type);
     updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12]
     break;
   }
   case R_AARCH64_ADR_PREL_LO21: {
-    uint64_t X = SA - P;
+    uint64_t X = Val;
     checkInt<21>(X, Type);
     updateAArch64Addr(Loc, X & 0x1FFFFF);
     break;
   }
   case R_AARCH64_ADR_PREL_PG_HI21:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: {
-    uint64_t X = getAArch64Page(SA) - getAArch64Page(P);
+    uint64_t X = Val;
     checkInt<33>(X, Type);
     updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12]
     break;
   }
   case R_AARCH64_CALL26:
   case R_AARCH64_JUMP26: {
-    uint64_t X = SA - P;
+    uint64_t X = Val;
     checkInt<28>(X, Type);
     or32le(Loc, (X & 0x0FFFFFFC) >> 2);
     break;
   }
   case R_AARCH64_CONDBR19: {
-    uint64_t X = SA - P;
+    uint64_t X = Val;
     checkInt<21>(X, Type);
     or32le(Loc, (X & 0x1FFFFC) << 3);
     break;
   }
   case R_AARCH64_LD64_GOT_LO12_NC:
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
-    checkAlignment<8>(SA, Type);
-    or32le(Loc, (SA & 0xFF8) << 7);
+    checkAlignment<8>(Val, Type);
+    or32le(Loc, (Val & 0xFF8) << 7);
     break;
   case R_AARCH64_LDST128_ABS_LO12_NC:
-    or32le(Loc, (SA & 0x0FF8) << 6);
+    or32le(Loc, (Val & 0x0FF8) << 6);
     break;
   case R_AARCH64_LDST16_ABS_LO12_NC:
-    or32le(Loc, (SA & 0x0FFC) << 9);
+    or32le(Loc, (Val & 0x0FFC) << 9);
     break;
   case R_AARCH64_LDST8_ABS_LO12_NC:
-    or32le(Loc, (SA & 0xFFF) << 10);
+    or32le(Loc, (Val & 0xFFF) << 10);
     break;
   case R_AARCH64_LDST32_ABS_LO12_NC:
-    or32le(Loc, (SA & 0xFFC) << 8);
+    or32le(Loc, (Val & 0xFFC) << 8);
     break;
   case R_AARCH64_LDST64_ABS_LO12_NC:
-    or32le(Loc, (SA & 0xFF8) << 7);
+    or32le(Loc, (Val & 0xFF8) << 7);
     break;
   case R_AARCH64_PREL16:
-    checkIntUInt<16>(SA - P, Type);
-    write16le(Loc, SA - P);
+    checkIntUInt<16>(Val, Type);
+    write16le(Loc, Val);
     break;
   case R_AARCH64_PREL32:
-    checkIntUInt<32>(SA - P, Type);
-    write32le(Loc, SA - P);
+    checkIntUInt<32>(Val, Type);
+    write32le(Loc, Val);
     break;
   case R_AARCH64_PREL64:
-    write64le(Loc, SA - P);
+    write64le(Loc, Val);
     break;
   case R_AARCH64_TSTBR14: {
-    uint64_t X = SA - P;
+    uint64_t X = Val;
     checkInt<16>(X, Type);
     or32le(Loc, (X & 0xFFFC) << 3);
     break;
   }
   case R_AARCH64_TLSLE_ADD_TPREL_HI12: {
-    uint64_t V = llvm::alignTo(TcbSize, Out<ELF64LE>::TlsPhdr->p_align) + SA;
+    uint64_t V = llvm::alignTo(TcbSize, Out<ELF64LE>::TlsPhdr->p_align) + Val;
     checkInt<24>(V, Type);
     updateAArch64Add(Loc, (V & 0xFFF000) >> 12);
     break;
   }
   case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: {
-    uint64_t V = llvm::alignTo(TcbSize, Out<ELF64LE>::TlsPhdr->p_align) + SA;
+    uint64_t V = llvm::alignTo(TcbSize, Out<ELF64LE>::TlsPhdr->p_align) + Val;
     updateAArch64Add(Loc, V & 0xFFF);
     break;
   }
@@ -1523,9 +1497,8 @@ void AArch64TargetInfo::relocateOne(uint
   }
 }
 
-size_t AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                         uint32_t Type, uint64_t P,
-                                         uint64_t SA) const {
+void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
+                                       uint64_t Val) const {
   // TLSDESC Global-Dynamic relocation are in the form:
   //   adrp    x0, :tlsdesc:v             [R_AARCH64_TLSDESC_ADR_PAGE21]
   //   ldr     x1, [x0, #:tlsdesc_lo12:v  [R_AARCH64_TLSDESC_LD64_LO12_NC]
@@ -1537,7 +1510,7 @@ size_t AArch64TargetInfo::relaxTlsGdToLe
   //   nop
   //   nop
   uint64_t TPOff = llvm::alignTo(TcbSize, Out<ELF64LE>::TlsPhdr->p_align);
-  uint64_t X = SA + TPOff;
+  uint64_t X = Val + TPOff;
   checkUInt<32>(X, Type);
 
   uint32_t NewInst;
@@ -1559,15 +1532,12 @@ size_t AArch64TargetInfo::relaxTlsGdToLe
     llvm_unreachable("unsupported Relocation for TLS GD to LE relax");
   }
   write32le(Loc, NewInst);
-
-  return 0;
 }
 
-size_t AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd,
-                                         uint32_t Type, uint64_t P,
-                                         uint64_t SA) const {
+void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
+                                       uint64_t Val) const {
   uint64_t TPOff = llvm::alignTo(TcbSize, Out<ELF64LE>::TlsPhdr->p_align);
-  uint64_t X = SA + TPOff;
+  uint64_t X = Val + TPOff;
   checkUInt<32>(X, Type);
 
   uint32_t Inst = read32le(Loc);
@@ -1584,16 +1554,18 @@ size_t AArch64TargetInfo::relaxTlsIeToLe
     llvm_unreachable("invalid Relocation for TLS IE to LE Relax");
   }
   write32le(Loc, NewInst);
-
-  return 0;
 }
 
 // Implementing relocations for AMDGPU is low priority since most
 // programs don't use relocations now. Thus, this function is not
 // actually called (relocateOne is called for each relocation).
 // That's why the AMDGPU port works without implementing this function.
-void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                   uint64_t P, uint64_t SA) const {
+void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
+                                   uint64_t Val) const {
+  llvm_unreachable("not implemented");
+}
+
+RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
   llvm_unreachable("not implemented");
 }
 
@@ -1611,6 +1583,31 @@ template <class ELFT> MipsTargetInfo<ELF
 }
 
 template <class ELFT>
+RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
+                                         const SymbolBody &S) const {
+  switch (Type) {
+  default:
+    return R_ABS;
+  case R_MIPS_HI16:
+    // MIPS _gp_disp designates offset between start of function and 'gp'
+    // pointer into GOT. __gnu_local_gp is equal to the current value of
+    // the 'gp'. Therefore any relocations against them do not require
+    // dynamic relocation.
+    if (&S == ElfSym<ELFT>::MipsGpDisp)
+      return R_PC;
+    return R_ABS;
+  case R_MIPS_PC32:
+  case R_MIPS_PC16:
+  case R_MIPS_PC19_S2:
+  case R_MIPS_PC21_S2:
+  case R_MIPS_PC26_S2:
+  case R_MIPS_PCHI16:
+  case R_MIPS_PCLO16:
+    return R_PC;
+  }
+}
+
+template <class ELFT>
 uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const {
   if (Type == R_MIPS_32 || Type == R_MIPS_64)
     return R_MIPS_REL32;
@@ -1659,11 +1656,9 @@ static int64_t getPcRelocAddend(const ui
 }
 
 template <endianness E, uint8_t BSIZE, uint8_t SHIFT>
-static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t P,
-                             uint64_t SA) {
+static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) {
   uint32_t Mask = 0xffffffff >> (32 - BSIZE);
   uint32_t Instr = read32<E>(Loc);
-  int64_t V = SA - P;
   if (SHIFT > 0)
     checkAlignment<(1 << SHIFT)>(V, Type);
   checkInt<BSIZE + SHIFT>(V, Type);
@@ -1813,9 +1808,8 @@ uint64_t MipsTargetInfo<ELFT>::getImplic
 }
 
 template <class ELFT>
-void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
-                                       uint32_t Type, uint64_t P,
-                                       uint64_t SA) const {
+void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
+                                       uint64_t Val) const {
   const endianness E = ELFT::TargetEndianness;
   // Thread pointer and DRP offsets from the start of TLS data area.
   // https://www.linux-mips.org/wiki/NPTL
@@ -1823,71 +1817,71 @@ void MipsTargetInfo<ELFT>::relocateOne(u
   const uint32_t DTPOffset = 0x8000;
   switch (Type) {
   case R_MIPS_32:
-    write32<E>(Loc, SA);
+    write32<E>(Loc, Val);
     break;
   case R_MIPS_26: {
     uint32_t Instr = read32<E>(Loc);
-    write32<E>(Loc, (Instr & ~0x3ffffff) | (SA >> 2));
+    write32<E>(Loc, (Instr & ~0x3ffffff) | (Val >> 2));
     break;
   }
   case R_MIPS_CALL16:
   case R_MIPS_GOT16: {
-    int64_t V = SA - getMipsGpAddr<ELFT>();
+    int64_t V = Val - getMipsGpAddr<ELFT>();
     if (Type == R_MIPS_GOT16)
       checkInt<16>(V, Type);
     writeMipsLo16<E>(Loc, V);
     break;
   }
   case R_MIPS_GPREL16: {
-    int64_t V = SA - getMipsGpAddr<ELFT>();
+    int64_t V = Val - getMipsGpAddr<ELFT>();
     checkInt<16>(V, Type);
     writeMipsLo16<E>(Loc, V);
     break;
   }
   case R_MIPS_GPREL32:
-    write32<E>(Loc, SA - getMipsGpAddr<ELFT>());
+    write32<E>(Loc, Val - getMipsGpAddr<ELFT>());
     break;
   case R_MIPS_HI16:
-    writeMipsHi16<E>(Loc, SA);
+    writeMipsHi16<E>(Loc, Val);
     break;
   case R_MIPS_JALR:
     // Ignore this optimization relocation for now
     break;
   case R_MIPS_LO16:
-    writeMipsLo16<E>(Loc, SA);
+    writeMipsLo16<E>(Loc, Val);
     break;
   case R_MIPS_PC16:
-    applyMipsPcReloc<E, 16, 2>(Loc, Type, P, SA);
+    applyMipsPcReloc<E, 16, 2>(Loc, Type, Val);
     break;
   case R_MIPS_PC19_S2:
-    applyMipsPcReloc<E, 19, 2>(Loc, Type, P, SA);
+    applyMipsPcReloc<E, 19, 2>(Loc, Type, Val);
     break;
   case R_MIPS_PC21_S2:
-    applyMipsPcReloc<E, 21, 2>(Loc, Type, P, SA);
+    applyMipsPcReloc<E, 21, 2>(Loc, Type, Val);
     break;
   case R_MIPS_PC26_S2:
-    applyMipsPcReloc<E, 26, 2>(Loc, Type, P, SA);
+    applyMipsPcReloc<E, 26, 2>(Loc, Type, Val);
     break;
   case R_MIPS_PC32:
-    applyMipsPcReloc<E, 32, 0>(Loc, Type, P, SA);
+    applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
     break;
   case R_MIPS_PCHI16:
-    writeMipsHi16<E>(Loc, SA - P);
+    writeMipsHi16<E>(Loc, Val);
     break;
   case R_MIPS_PCLO16:
-    writeMipsLo16<E>(Loc, SA - P);
+    writeMipsLo16<E>(Loc, Val);
     break;
   case R_MIPS_TLS_DTPREL_HI16:
-    writeMipsHi16<E>(Loc, SA - DTPOffset);
+    writeMipsHi16<E>(Loc, Val - DTPOffset);
     break;
   case R_MIPS_TLS_DTPREL_LO16:
-    writeMipsLo16<E>(Loc, SA - DTPOffset);
+    writeMipsLo16<E>(Loc, Val - DTPOffset);
     break;
   case R_MIPS_TLS_TPREL_HI16:
-    writeMipsHi16<E>(Loc, SA - TPOffset);
+    writeMipsHi16<E>(Loc, Val - TPOffset);
     break;
   case R_MIPS_TLS_TPREL_LO16:
-    writeMipsLo16<E>(Loc, SA - TPOffset);
+    writeMipsLo16<E>(Loc, Val - TPOffset);
     break;
   default:
     fatal("unrecognized reloc " + Twine(Type));

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Tue Apr 12 20:40:19 2016
@@ -10,6 +10,7 @@
 #ifndef LLD_ELF_TARGET_H
 #define LLD_ELF_TARGET_H
 
+#include "InputSection.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/ELF.h"
 
@@ -68,16 +69,15 @@ public:
 
   virtual void writeThunk(uint8_t *Buf, uint64_t S) const {}
 
-  virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                           uint64_t P, uint64_t SA) const = 0;
+  virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const = 0;
+  virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;
   virtual bool isGotRelative(uint32_t Type) const;
   bool canRelaxTls(uint32_t Type, const SymbolBody *S) const;
   template <class ELFT>
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const;
-  size_t relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                  uint64_t SA, const SymbolBody &S) const;
   virtual ~TargetInfo();
 
+  unsigned TlsGdToLeSkip = 1;
   unsigned PageSize = 4096;
 
   // On freebsd x86_64 the first page cannot be mmaped.
@@ -103,18 +103,14 @@ public:
   uint32_t ThunkSize = 0;
   bool UseLazyBinding = false;
 
+  virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+  virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const;
+
 private:
   virtual bool needsCopyRelImpl(uint32_t Type) const;
   virtual bool needsPltImpl(uint32_t Type) const;
-
-  virtual size_t relaxTlsGdToIe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const;
-  virtual size_t relaxTlsGdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const;
-  virtual size_t relaxTlsIeToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const;
-  virtual size_t relaxTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const;
 };
 
 uint64_t getPPC64TocBase();

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Tue Apr 12 20:40:19 2016
@@ -17,6 +17,7 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Endian.h"
 #include "llvm/Support/FileOutputBuffer.h"
 #include "llvm/Support/StringSaver.h"
 #include "llvm/Support/raw_ostream.h"
@@ -24,6 +25,7 @@
 using namespace llvm;
 using namespace llvm::ELF;
 using namespace llvm::object;
+using namespace llvm::support::endian;
 
 using namespace lld;
 using namespace lld::elf;
@@ -268,23 +270,40 @@ template <bool Is64Bits> struct DenseMap
 }
 
 // Returns the number of relocations processed.
-template <class ELFT, class RelT>
+template <class ELFT>
 static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
-                                    InputSectionBase<ELFT> &C, RelT &RI) {
+                                    InputSectionBase<ELFT> &C,
+                                    typename ELFT::uint Offset,
+                                    typename ELFT::uint Addend, RelExpr Expr) {
+  if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
+    return 0;
+
   typedef typename ELFT::uint uintX_t;
   if (Target->pointsToLocalDynamicGotEntry(Type)) {
-    if (Target->canRelaxTls(Type, nullptr))
+    if (Target->canRelaxTls(Type, nullptr)) {
+      C.Relocations.push_back(
+          {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
       return 2;
+    }
     if (Out<ELFT>::Got->addTlsIndex())
       Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got,
                                     Out<ELFT>::Got->getTlsIndexOff(), false,
                                     nullptr, 0});
+    Expr = Expr == R_PC ? R_TLSLD_PC : R_TLSLD;
+    C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
     return 1;
   }
 
   if (!Body.isTls())
     return 0;
 
+  if (Target->isTlsLocalDynamicRel(Type) &&
+      Target->canRelaxTls(Type, nullptr)) {
+    C.Relocations.push_back(
+        {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body});
+    return 1;
+  }
+
   if (Target->isTlsGlobalDynamicRel(Type)) {
     if (!Target->canRelaxTls(Type, &Body)) {
       if (Out<ELFT>::Got->addDynTlsEntry(Body)) {
@@ -295,17 +314,30 @@ static unsigned handleTlsRelocation(uint
                                       Off + (uintX_t)sizeof(uintX_t), false,
                                       &Body, 0});
       }
+      Expr = Expr == R_PC ? R_TLSGD_PC : R_TLSGD;
+      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
       return 1;
     }
-    if (!Body.isPreemptible())
+
+    if (Body.isPreemptible()) {
+      Expr = Expr == R_PC ? R_RELAX_TLS_GD_TO_IE_PC : R_RELAX_TLS_GD_TO_IE;
+      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+      if (!Body.isInGot()) {
+        Out<ELFT>::Got->addEntry(Body);
+        Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
+                                      Body.getGotOffset<ELFT>(), false, &Body,
+                                      0});
+      }
       return 2;
-    if (!Body.isInGot()) {
-      Out<ELFT>::Got->addEntry(Body);
-      Out<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, Out<ELFT>::Got,
-                                    Body.getGotOffset<ELFT>(), false, &Body,
-                                    0});
     }
-    return 2;
+    C.Relocations.push_back(
+        {R_RELAX_TLS_GD_TO_LE, Type, Offset, Addend, &Body});
+    return Target->TlsGdToLeSkip;
+  }
+  if (Target->isTlsInitialExecRel(Type) && Target->canRelaxTls(Type, &Body)) {
+    C.Relocations.push_back(
+        {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
+    return 1;
   }
   return 0;
 }
@@ -329,6 +361,56 @@ void Writer<ELFT>::scanRelocsForThunks(c
   }
 }
 
+template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) {
+  return read32<E>(Loc) & 0xffff;
+}
+
+template <class RelTy>
+static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
+  switch (Rel->getType(Config->Mips64EL)) {
+  case R_MIPS_HI16:
+    return R_MIPS_LO16;
+  case R_MIPS_GOT16:
+    return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
+  case R_MIPS_PCHI16:
+    return R_MIPS_PCLO16;
+  case R_MICROMIPS_HI16:
+    return R_MICROMIPS_LO16;
+  default:
+    return R_MIPS_NONE;
+  }
+}
+
+template <class ELFT, class RelTy>
+static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
+                                    SymbolBody &Sym, const RelTy *Rel,
+                                    const RelTy *End) {
+  uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
+  uint32_t Type = getMipsPairType(Rel, Sym);
+
+  // Some MIPS relocations use addend calculated from addend of the relocation
+  // itself and addend of paired relocation. ABI requires to compute such
+  // combined addend in case of REL relocation record format only.
+  // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (RelTy::IsRela || Type == R_MIPS_NONE)
+    return 0;
+
+  for (const RelTy *RI = Rel; RI != End; ++RI) {
+    if (RI->getType(Config->Mips64EL) != Type)
+      continue;
+    if (RI->getSymbol(Config->Mips64EL) != SymIndex)
+      continue;
+    const endianness E = ELFT::TargetEndianness;
+    return ((read32<E>(BufLoc) & 0xffff) << 16) +
+           readSignedLo16<E>(Buf + RI->r_offset);
+  }
+  unsigned OldType = Rel->getType(Config->Mips64EL);
+  StringRef OldName = getELFRelocationTypeName(Config->EMachine, OldType);
+  StringRef NewName = getELFRelocationTypeName(Config->EMachine, Type);
+  warning("can't find matching " + NewName + " relocation for " + OldName);
+  return 0;
+}
+
 // The reason we have to do this early scan is as follows
 // * To mmap the output file, we need to know the size
 // * For that, we need to know how many dynamic relocs we will have.
@@ -345,7 +427,16 @@ void Writer<ELFT>::scanRelocsForThunks(c
 template <class ELFT>
 template <class RelTy>
 void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
+  bool IsAlloc = C.getSectionHdr()->sh_flags & SHF_ALLOC;
+
+  auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
+    if (IsAlloc)
+      Out<ELFT>::RelaDyn->addReloc(Reloc);
+  };
+
   const elf::ObjectFile<ELFT> &File = *C.getFile();
+  ArrayRef<uint8_t> SectionData = C.getSectionData();
+  const uint8_t *Buf = SectionData.begin();
   for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
     const RelTy &RI = *I;
     uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
@@ -369,22 +460,33 @@ void Writer<ELFT>::scanRelocs(InputSecti
       if (auto *S = dyn_cast<SharedSymbol<ELFT>>(&Body))
         S->File->IsUsed = true;
 
+    RelExpr Expr = Target->getRelExpr(Type, Body);
+
+    uintX_t Addend = getAddend<ELFT>(RI);
+    const uint8_t *BufLoc = Buf + RI.r_offset;
+    if (!RelTy::IsRela)
+      Addend += Target->getImplicitAddend(BufLoc, Type);
+    if (Config->EMachine == EM_MIPS)
+      Addend += findMipsPairedAddend<ELFT>(Buf, BufLoc, Body, &RI, E);
+
     bool Preemptible = Body.isPreemptible();
-    if (unsigned Processed = handleTlsRelocation<ELFT>(Type, Body, C, RI)) {
+    if (unsigned Processed =
+            handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
       I += (Processed - 1);
       continue;
     }
 
     if (Target->needsDynRelative(Type))
-      Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, C.OutSec, Offset, true,
-                                    &Body, getAddend<ELFT>(RI)});
+      AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body,
+              getAddend<ELFT>(RI)});
 
     // If a symbol in a DSO is referenced directly instead of through GOT,
     // we need to create a copy relocation for the symbol.
     if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body)) {
-      if (Target->needsCopyRel<ELFT>(Type, Body)) {
+      if (IsAlloc && Target->needsCopyRel<ELFT>(Type, *B)) {
         if (!B->needsCopy())
           addCopyRelSymbol(B);
+        C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
         continue;
       }
     }
@@ -395,6 +497,15 @@ void Writer<ELFT>::scanRelocs(InputSecti
     if (NeedPlt) {
       if (NeedPlt == TargetInfo::Plt_Implicit)
         Body.NeedsCopyOrPltAddr = true;
+      RelExpr E;
+      if (Expr == R_PPC_OPD)
+        E = R_PPC_PLT_OPD;
+      else if (Expr == R_PC)
+        E = R_PLT_PC;
+      else
+        E = R_PLT;
+      C.Relocations.push_back({E, Type, Offset, Addend, &Body});
+
       if (Body.isInPlt())
         continue;
       Out<ELFT>::Plt->addEntry(Body);
@@ -407,22 +518,43 @@ void Writer<ELFT>::scanRelocs(InputSecti
 
       if (Target->UseLazyBinding) {
         Out<ELFT>::GotPlt->addEntry(Body);
-        Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
-                                      Body.getGotPltOffset<ELFT>(),
-                                      !Preemptible, &Body, 0});
+        if (IsAlloc)
+          Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
+                                        Body.getGotPltOffset<ELFT>(),
+                                        !Preemptible, &Body, 0});
       } else {
         if (Body.isInGot())
           continue;
         Out<ELFT>::Got->addEntry(Body);
-        Out<ELFT>::RelaDyn->addReloc({Rel, Out<ELFT>::Got,
-                                      Body.getGotOffset<ELFT>(), !Preemptible,
-                                      &Body, 0});
+        AddDyn({Rel, Out<ELFT>::Got, Body.getGotOffset<ELFT>(), !Preemptible,
+                &Body, 0});
       }
       continue;
     }
 
+    if (Target->needsThunk(Type, File, Body)) {
+      C.Relocations.push_back({R_THUNK, Type, Offset, Addend, &Body});
+      continue;
+    }
+
     // If a relocation needs GOT, we create a GOT slot for the symbol.
     if (Target->needsGot(Type, Body)) {
+      uint32_t T = Body.isTls() ? Target->getTlsGotRel(Type) : Type;
+      RelExpr E;
+      if (Expr == R_PC)
+        E = R_GOT_PC;
+      else if (Expr == R_PAGE_PC)
+        E = R_GOT_PAGE_PC;
+      else if (Config->EMachine == EM_MIPS) {
+        if (Body.isLocal())
+          E = R_MIPS_GOT_LOCAL;
+        else if (!Body.isPreemptible())
+          E = R_MIPS_GOT;
+        else
+          E = R_GOT;
+      } else
+        E = R_GOT;
+      C.Relocations.push_back({E, T, Offset, Addend, &Body});
       if (Body.isInGot())
         continue;
       Out<ELFT>::Got->addEntry(Body);
@@ -443,26 +575,23 @@ void Writer<ELFT>::scanRelocs(InputSecti
           DynType = Target->GotRel;
         else
           DynType = Target->RelativeRel;
-        Out<ELFT>::RelaDyn->addReloc({DynType, Out<ELFT>::Got,
-                                      Body.getGotOffset<ELFT>(), !Preemptible,
-                                      &Body, 0});
+        AddDyn({DynType, Out<ELFT>::Got, Body.getGotOffset<ELFT>(),
+                !Preemptible, &Body, 0});
       }
       continue;
     }
 
-    // MIPS _gp_disp designates offset between start of function and 'gp'
-    // pointer into GOT. __gnu_local_gp is equal to the current value of
-    // the 'gp'. Therefore any relocations against them do not require
-    // dynamic relocation.
-    if (Config->EMachine == EM_MIPS && (&Body == ElfSym<ELFT>::MipsGpDisp ||
-                                        &Body == ElfSym<ELFT>::MipsLocalGp))
-      continue;
-
     if (Preemptible) {
       // We don't know anything about the finaly symbol. Just ask the dynamic
       // linker to handle the relocation for us.
-      Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), C.OutSec, Offset,
-                                    false, &Body, getAddend<ELFT>(RI)});
+      AddDyn({Target->getDynRel(Type), C.OutSec, Offset, false, &Body, Addend});
+      continue;
+    }
+
+    if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
+      C.Relocations.push_back({R_PPC_TOC, Type, Offset, Addend, &Body});
+      AddDyn({R_PPC64_RELATIVE, C.OutSec, Offset, false, nullptr,
+              (uintX_t)getPPC64TocBase() + Addend});
       continue;
     }
 
@@ -473,18 +602,20 @@ void Writer<ELFT>::scanRelocs(InputSecti
     // We can however do better than just copying the incoming relocation. We
     // can process some of it and and just ask the dynamic linker to add the
     // load address.
-    if (!Config->Pic || Target->isRelRelative(Type) || Target->isSizeRel(Type))
+    if (Target->isSizeRel(Type)) {
+      C.Relocations.push_back({R_SIZE, Type, Offset, Addend, &Body});
       continue;
-
-    uintX_t Addend = getAddend<ELFT>(RI);
-    if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
-      Out<ELFT>::RelaDyn->addReloc({R_PPC64_RELATIVE, C.OutSec, Offset, false,
-                                    nullptr,
-                                    (uintX_t)getPPC64TocBase() + Addend});
+    }
+    if (!Config->Pic || Target->isRelRelative(Type) || Expr == R_PC) {
+      if (Config->EMachine == EM_MIPS && Body.isLocal() &&
+          (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
+        Expr = R_MIPS_GP0;
+      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
       continue;
     }
-    Out<ELFT>::RelaDyn->addReloc(
-        {Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend});
+
+    AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body, Addend});
+    C.Relocations.push_back({R_ABS, Type, Offset, Addend, &Body});
   }
 
   // Scan relocations for necessary thunks.
@@ -493,9 +624,8 @@ void Writer<ELFT>::scanRelocs(InputSecti
 }
 
 template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
-  if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
-    for (const Elf_Shdr *RelSec : C.RelocSections)
-      scanRelocs(C, *RelSec);
+  for (const Elf_Shdr *RelSec : C.RelocSections)
+    scanRelocs(C, *RelSec);
 }
 
 template <class ELFT>

Modified: lld/trunk/test/ELF/tls-opt.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/tls-opt.s?rev=266158&r1=266157&r2=266158&view=diff
==============================================================================
--- lld/trunk/test/ELF/tls-opt.s (original)
+++ lld/trunk/test/ELF/tls-opt.s Tue Apr 12 20:40:19 2016
@@ -22,9 +22,9 @@
 // DISASM-NEXT: 1104d: 49 81 c4 fc ff ff ff addq $-4, %r12
 // Corrupred output:
 // DISASM-NEXT: 11054: 48 8d 80 f8 ff ff ff leaq -8(%rax), %rax
-// DISASM-NEXT: 1105b: 48 d1 81 c4 f8 ff ff rolq -1852(%rcx)
+// DISASM-NEXT: 1105b: 48 d1 81 c4 fc ff ff rolq -828(%rcx)
 // DISASM-NEXT: 11062: ff 48 d1 decl -47(%rax)
-// DISASM-NEXT: 11065: 81 c4 f8 ff ff ff addl $4294967288, %esp
+// DISASM-NEXT: 11065: 81 c4 fc ff ff ff addl $4294967292, %esp
 // LD to LE:
 // DISASM-NEXT: 1106b: 66 66 66 64 48 8b 04 25 00 00 00 00 movq %fs:0, %rax
 // DISASM-NEXT: 11077: 48 8d 88 f8 ff ff ff                leaq -8(%rax), %rcx




More information about the llvm-commits mailing list