[lld] r259829 - Avoid code duplication when creating dynamic relocations.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 4 13:33:05 PST 2016


Author: rafael
Date: Thu Feb  4 15:33:05 2016
New Revision: 259829

URL: http://llvm.org/viewvc/llvm-project?rev=259829&view=rev
Log:
Avoid code duplication when creating dynamic relocations.

Another case where we currently have almost duplicated code is the
creation of dynamic relocations. First to decide if we need one, then to
decide what to write.

This patch fixes it by passing more information from the relocation scan
to the section writing code. This is the same idea used for r258723.

I actually think it should be possible to simplify this further by
reordering things a bit in the writer. For example, we should be able to
represent almost every position in the file with an OutputSeciton and
offset. When writing it out we then just need to add the offset to the
OutputSection VA.

Modified:
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=259829&r1=259828&r2=259829&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Feb  4 15:33:05 2016
@@ -213,123 +213,50 @@ RelocationSection<ELFT>::RelocationSecti
   this->Header.sh_addralign = sizeof(uintX_t);
 }
 
-// Applies corresponding symbol and type for dynamic tls relocation.
-// Returns true if relocation was handled.
 template <class ELFT>
-bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
-                                                   uint32_t Type, Elf_Rel *P,
-                                                   Elf_Rel *N) {
-  if (Target->isTlsLocalDynamicRel(Type)) {
-    P->setSymbolAndType(0, Target->TlsModuleIndexRel, Config->Mips64EL);
-    P->r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
-    return true;
+static typename ELFFile<ELFT>::uintX_t
+getOffset(const DynamicReloc<ELFT> &Rel) {
+  typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+  SymbolBody *Sym = Rel.Sym;
+  switch (Rel.OKind) {
+  case DynamicReloc<ELFT>::Off_GTlsIndex:
+    return Out<ELFT>::Got->getGlobalDynAddr(*Sym);
+  case DynamicReloc<ELFT>::Off_GTlsOffset:
+    return Out<ELFT>::Got->getGlobalDynAddr(*Sym) + sizeof(uintX_t);
+  case DynamicReloc<ELFT>::Off_LTlsIndex:
+    return Out<ELFT>::Got->getLocalTlsIndexVA();
+  case DynamicReloc<ELFT>::Off_Sec:
+    return Rel.OffsetSec->getOffset(Rel.OffsetInSec) +
+           Rel.OffsetSec->OutSec->getVA();
+  case DynamicReloc<ELFT>::Off_Bss:
+    return cast<SharedSymbol<ELFT>>(Sym)->OffsetInBss + Out<ELFT>::Bss->getVA();
+  case DynamicReloc<ELFT>::Off_Got:
+    return Sym->getGotVA<ELFT>();
+  case DynamicReloc<ELFT>::Off_GotPlt:
+    return Sym->getGotPltVA<ELFT>();
   }
-
-  if (!Body || !Target->isTlsGlobalDynamicRel(Type))
-    return false;
-
-  if (Target->canRelaxTls(Type, Body)) {
-    P->setSymbolAndType(Body->DynsymIndex, Target->getTlsGotRel(),
-                        Config->Mips64EL);
-    P->r_offset = Body->getGotVA<ELFT>();
-    return true;
-  }
-
-  P->setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel,
-                      Config->Mips64EL);
-  P->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
-  N->setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel,
-                      Config->Mips64EL);
-  N->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
-  return true;
+  llvm_unreachable("Invalid offset kind");
 }
 
 template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
   for (const DynamicReloc<ELFT> &Rel : Relocs) {
     auto *P = reinterpret_cast<Elf_Rel *>(Buf);
     Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
-
-    // Skip placeholder for global dynamic TLS relocation pair. It was already
-    // handled by the previous relocation.
-    if (!Rel.C)
-      continue;
-
-    InputSectionBase<ELFT> &C = *Rel.C;
-    const Elf_Rel &RI = *Rel.RI;
-    uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
-    const ObjectFile<ELFT> &File = *C.getFile();
-    SymbolBody *Body = File.getSymbolBody(SymIndex);
-    if (Body)
-      Body = Body->repl();
-
-    uint32_t Type = RI.getType(Config->Mips64EL);
-    if (applyTlsDynamicReloc(Body, Type, P, reinterpret_cast<Elf_Rel *>(Buf)))
-      continue;
-
-    // Writer::scanRelocs creates a RELATIVE reloc for some type of TLS reloc.
-    // We want to write it down as is.
-    if (Type == Target->RelativeRel) {
-      P->setSymbolAndType(0, Type, Config->Mips64EL);
-      P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
-      continue;
-    }
-
-    // Emit a copy relocation.
-    auto *SS = dyn_cast_or_null<SharedSymbol<ELFT>>(Body);
-    if (SS && SS->NeedsCopy) {
-      P->setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL);
-      P->r_offset = Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
-      continue;
-    }
-
-    bool NeedsGot = Body && Target->needsGot(Type, *Body);
-    bool CBP = canBePreempted(Body, NeedsGot);
+    SymbolBody *Sym = Rel.Sym;
 
     if (IsRela) {
-      auto R = static_cast<const Elf_Rela &>(RI);
-      auto S = static_cast<Elf_Rela *>(P);
-      uintX_t A = NeedsGot ? 0 : R.r_addend;
-      if (CBP)
-        S->r_addend = A;
-      else if (Body)
-        S->r_addend = Body->getVA<ELFT>() + A;
-      else
-        S->r_addend = getLocalRelTarget(File, R, A);
+      uintX_t VA = 0;
+      if (Rel.UseSymVA)
+        VA = Sym->getVA<ELFT>();
+      else if (Rel.TargetSec)
+        VA = Rel.TargetSec->getOffset(Rel.OffsetInTargetSec) +
+             Rel.TargetSec->OutSec->getVA();
+      reinterpret_cast<Elf_Rela *>(P)->r_addend = Rel.Addend + VA;
     }
 
-    // For a symbol with STT_GNU_IFUNC type, we always create a PLT and
-    // a GOT entry for the symbol, and emit an IRELATIVE reloc rather than
-    // the usual JUMP_SLOT reloc for the GOT entry. For the details, you
-    // want to read http://www.airs.com/blog/archives/403
-    if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) {
-      P->setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL);
-      if (Out<ELFT>::GotPlt)
-        P->r_offset = Body->getGotPltVA<ELFT>();
-      else
-        P->r_offset = Body->getGotVA<ELFT>();
-      continue;
-    }
-
-    bool LazyReloc =
-        Body && Target->UseLazyBinding && Target->needsPlt(Type, *Body);
-
-    unsigned Reloc;
-    if (!CBP)
-      Reloc = Target->RelativeRel;
-    else if (LazyReloc)
-      Reloc = Target->PltRel;
-    else if (NeedsGot)
-      Reloc = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel;
-    else
-      Reloc = Target->getDynRel(Type);
-    P->setSymbolAndType(CBP ? Body->DynsymIndex : 0, Reloc, Config->Mips64EL);
-
-    if (LazyReloc)
-      P->r_offset = Body->getGotPltVA<ELFT>();
-    else if (NeedsGot)
-      P->r_offset = Body->getGotVA<ELFT>();
-    else
-      P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+    P->r_offset = getOffset(Rel);
+    uint32_t SymIdx = (!Rel.UseSymVA && Sym) ? Sym->DynsymIndex : 0;
+    P->setSymbolAndType(SymIdx, Rel.Type, Config->Mips64EL);
   }
 }
 

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=259829&r1=259828&r2=259829&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Feb  4 15:33:05 2016
@@ -172,9 +172,46 @@ private:
 };
 
 template <class ELFT> struct DynamicReloc {
-  typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
-  InputSectionBase<ELFT> *C;
-  const Elf_Rel *RI;
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+  uint32_t Type;
+
+  // Where the relocation is.
+  enum OffsetKind {
+    Off_Got,       // The got entry of Sym.
+    Off_GotPlt,    // The got.plt entry of Sym.
+    Off_Bss,       // The bss entry of Sym (copy reloc).
+    Off_Sec,       // The final position of the given input section and offset.
+    Off_LTlsIndex, // The local tls index.
+    Off_GTlsIndex, // The global tls index of Sym.
+    Off_GTlsOffset // The global tls offset of Sym.
+  } OKind;
+
+  SymbolBody *Sym = nullptr;
+  InputSectionBase<ELFT> *OffsetSec = nullptr;
+  uintX_t OffsetInSec = 0;
+  bool UseSymVA = false;
+  InputSectionBase<ELFT> *TargetSec = nullptr;
+  uintX_t OffsetInTargetSec = 0;
+  uintX_t Addend = 0;
+
+  DynamicReloc(uint32_t Type, OffsetKind OKind, SymbolBody *Sym)
+      : Type(Type), OKind(OKind), Sym(Sym) {}
+
+  DynamicReloc(uint32_t Type, OffsetKind OKind, bool UseSymVA, SymbolBody *Sym)
+      : Type(Type), OKind(OKind), Sym(Sym), UseSymVA(UseSymVA) {}
+
+  DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
+               uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+               uintX_t Addend)
+      : Type(Type), OKind(Off_Sec), Sym(Sym), OffsetSec(OffsetSec),
+        OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {}
+
+  DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
+               uintX_t OffsetInSec, InputSectionBase<ELFT> *TargetSec,
+               uintX_t OffsetInTargetSec, uintX_t Addend)
+      : Type(Type), OKind(Off_Sec), OffsetSec(OffsetSec),
+        OffsetInSec(OffsetInSec), TargetSec(TargetSec),
+        OffsetInTargetSec(OffsetInTargetSec), Addend(Addend) {}
 };
 
 template <class ELFT>
@@ -228,9 +265,6 @@ public:
   bool Static = false;
 
 private:
-  bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P,
-                            Elf_Rel *N);
-
   std::vector<DynamicReloc<ELFT>> Relocs;
   const bool IsRela;
 };

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=259829&r1=259828&r2=259829&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Feb  4 15:33:05 2016
@@ -219,7 +219,9 @@ static bool handleTlsRelocation(unsigned
     if (Target->canRelaxTls(Type, nullptr))
       return true;
     if (Out<ELFT>::Got->addCurrentModuleTlsIndex())
-      Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+      Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel,
+                                    DynamicReloc<ELFT>::Off_LTlsIndex,
+                                    nullptr});
     return true;
   }
 
@@ -229,8 +231,10 @@ static bool handleTlsRelocation(unsigned
   if (Target->isTlsGlobalDynamicRel(Type)) {
     bool Opt = Target->canRelaxTls(Type, Body);
     if (!Opt && Out<ELFT>::Got->addDynTlsEntry(Body)) {
-      Out<ELFT>::RelaDyn->addReloc({&C, &RI});
-      Out<ELFT>::RelaDyn->addReloc({nullptr, nullptr});
+      Out<ELFT>::RelaDyn->addReloc(
+          {Target->TlsModuleIndexRel, DynamicReloc<ELFT>::Off_GTlsIndex, Body});
+      Out<ELFT>::RelaDyn->addReloc(
+          {Target->TlsOffsetRel, DynamicReloc<ELFT>::Off_GTlsOffset, Body});
       Body->setUsedInDynamicReloc();
       return true;
     }
@@ -283,12 +287,9 @@ void Writer<ELFT>::scanRelocs(
     if (handleTlsRelocation<ELFT>(Type, Body, C, RI))
       continue;
 
-    if (Target->needsDynRelative(Type)) {
-      RelType *Rel = new (Alloc) RelType;
-      Rel->setSymbolAndType(0, Target->RelativeRel, Config->Mips64EL);
-      Rel->r_offset = RI.r_offset;
-      Out<ELFT>::RelaDyn->addReloc({&C, Rel});
-    }
+    if (Target->needsDynRelative(Type))
+      Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true,
+                                    Body, getAddend<ELFT>(RI)});
 
     // MIPS has a special rule to create GOTs for local symbols.
     if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true)) {
@@ -307,7 +308,8 @@ void Writer<ELFT>::scanRelocs(
       if (Target->needsCopyRel(Type, *B)) {
         B->NeedsCopy = true;
         B->setUsedInDynamicReloc();
-        Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+        Out<ELFT>::RelaDyn->addReloc(
+            {Target->CopyRel, DynamicReloc<ELFT>::Off_Bss, B});
         continue;
       }
     }
@@ -320,12 +322,17 @@ void Writer<ELFT>::scanRelocs(
       if (Body->isInGot())
         continue;
       Out<ELFT>::Plt->addEntry(Body);
+      bool CBP = canBePreempted(Body, /*NeedsGot=*/true);
       if (Target->UseLazyBinding) {
         Out<ELFT>::GotPlt->addEntry(Body);
-        Out<ELFT>::RelaPlt->addReloc({&C, &RI});
+        Out<ELFT>::RelaPlt->addReloc(
+            {CBP ? Target->PltRel : Target->IRelativeRel,
+             DynamicReloc<ELFT>::Off_GotPlt, !CBP, Body});
       } else {
         Out<ELFT>::Got->addEntry(Body);
-        Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+        Out<ELFT>::RelaDyn->addReloc(
+            {CBP ? Target->PltRel : Target->IRelativeRel,
+             DynamicReloc<ELFT>::Off_Got, !CBP, Body});
       }
       continue;
     }
@@ -339,12 +346,14 @@ void Writer<ELFT>::scanRelocs(
 
       if (Target->UseLazyBinding) {
         Out<ELFT>::GotPlt->addEntry(Body);
-        Out<ELFT>::RelaPlt->addReloc({&C, &RI});
+        Out<ELFT>::RelaPlt->addReloc(
+            {Target->PltRel, DynamicReloc<ELFT>::Off_GotPlt, Body});
       } else {
         if (Body->isInGot())
           continue;
         Out<ELFT>::Got->addEntry(Body);
-        Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+        Out<ELFT>::RelaDyn->addReloc(
+            {Target->GotRel, DynamicReloc<ELFT>::Off_Got, Body});
       }
 
       if (canBePreempted(Body, /*NeedsGot=*/true))
@@ -373,8 +382,15 @@ void Writer<ELFT>::scanRelocs(
                     !Target->isSizeRel(Type);
       if (CBP)
         Body->setUsedInDynamicReloc();
-      if (CBP || Dynrel)
-        Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+      if (CBP || Dynrel) {
+        uint32_t DynType;
+        if (CBP)
+          DynType = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel;
+        else
+          DynType = Target->RelativeRel;
+        Out<ELFT>::RelaDyn->addReloc(
+            {DynType, DynamicReloc<ELFT>::Off_Got, !CBP, Body});
+      }
       continue;
     }
 
@@ -395,24 +411,48 @@ void Writer<ELFT>::scanRelocs(
         continue;
     }
 
-    // We get here if a program was not compiled as PIC.
     if (canBePreempted(Body, /*NeedsGot=*/false)) {
+      // We don't know anything about the finaly symbol. Just ask the dynamic
+      // linker to handle the relocation for us.
       Body->setUsedInDynamicReloc();
-      Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+      Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), &C, RI.r_offset,
+                                    false, Body, getAddend<ELFT>(RI)});
       continue;
     }
 
-    // If we get here, the code we are handling is not PIC. We need to copy
-    // relocations from object files to the output file, so that the
-    // dynamic linker can fix up addresses. But there are a few exceptions.
-    // If the relocation will not change at runtime, we don't need to copy
-    // them. For example, we don't copy PC-relative relocations because
-    // the distance between two symbols won't change whereever they are
-    // loaded. Likewise, if we are linking an executable, it will be loaded
-    // at a fixed address, so we don't copy relocations.
-    if (Config->Shared && !Target->isRelRelative(Type) &&
-        !Target->isSizeRel(Type))
-      Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+    // We know that this is the final symbol. If the program being produced
+    // is position independent, the final value is still not known.
+    // If the relocation depends on the symbol value (not the size or distances
+    // in the output), we still need some help from the dynamic linker.
+    // 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->Shared || Target->isRelRelative(Type) ||
+        Target->isSizeRel(Type))
+      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, RI.r_offset, false,
+                                    nullptr,
+                                    (uintX_t)getPPC64TocBase() + Addend});
+      continue;
+    }
+    if (Body) {
+      Out<ELFT>::RelaDyn->addReloc(
+          {Target->RelativeRel, &C, RI.r_offset, true, Body, Addend});
+      continue;
+    }
+    const Elf_Sym *Sym =
+        File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
+    InputSectionBase<ELFT> *Section = File.getSection(*Sym);
+    uintX_t Offset = Sym->st_value;
+    if (Sym->getType() == STT_SECTION) {
+      Offset += Addend;
+      Addend = 0;
+    }
+    Out<ELFT>::RelaDyn->addReloc(
+        {Target->RelativeRel, &C, RI.r_offset, Section, Offset, Addend});
   }
 }
 
@@ -906,6 +946,9 @@ template <class ELFT> bool Writer<ELFT>:
   for (OutputSectionBase<ELFT> *Sec : RegularSections)
     addStartStopSymbols(Sec);
 
+  // Define __rel[a]_iplt_{start,end} symbols if needed.
+  addRelIpltSymbols();
+
   // Scan relocations. This must be done after every symbol is declared so that
   // we can correctly decide if a dynamic relocation is needed.
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
@@ -920,9 +963,6 @@ template <class ELFT> bool Writer<ELFT>:
     }
   }
 
-  // Define __rel[a]_iplt_{start,end} symbols if needed.
-  addRelIpltSymbols();
-
   // Now that we have defined all possible symbols including linker-
   // synthesized ones. Visit all symbols to give the finishing touches.
   std::vector<DefinedCommon *> CommonSymbols;




More information about the llvm-commits mailing list