[ELF2] getLocalRelTarget should handle R_PPC64_TOC directly

R_PPC64_TOC does not have an associated symbol, but does have a non-zero VA
that target-specific code must compute using some non-trivial rule. We
handled this as a special case in PPC64TargetInfo::relocateOne, where
we knew to write this special address, but that did not work when creating shared
libraries. The special TOC address needs to be the subject of a
R_PPC64_RELATIVE relocation, and so we also need to know how to encode this
special address in the addend of that relocation.

Thus, some target-specific logic is necessary when creating R_PPC64_RELATIVE as
well. To solve this problem, we teach getLocalRelTarget to handle R_PPC64_TOC
as a special case. This allows us to remove the special case in
PPC64TargetInfo::relocateOne (simplifying code there), and naturally allows the
existing logic to do the right thing when creating associated R_PPC64_RELATIVE
relocations for shared libraries.

llvm-svn: 250555
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 7f7b970..a8545c3 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -126,7 +126,7 @@
         if (Body)
           Addend += getSymVA<ELFT>(cast<ELFSymbolBody<ELFT>>(*Body));
         else
-          Addend += getLocalRelTarget(File, RI);
+          Addend += getLocalRelTarget(File, RI, Type);
       }
       P->setSymbolAndType(0, Target->getRelativeReloc(), IsMips64EL);
     }
@@ -424,15 +424,19 @@
 template <class ELFT>
 typename ELFFile<ELFT>::uintX_t
 lld::elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
-                             const typename ELFFile<ELFT>::Elf_Rel &RI) {
+                             const typename ELFFile<ELFT>::Elf_Rel &RI,
+                             uint32_t Type) {
+  // PPC64 has a special relocation representing the TOC base pointer
+  // that does not have a corresponding symbol.
+  if (Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
+    return getPPC64TocBase();
+
   typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
   const Elf_Sym *Sym =
       File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
 
-  // For certain special relocations, such as R_PPC64_TOC, there's no
-  // corresponding symbol. Just return 0 in that case.
   if (!Sym)
-    return 0;
+    error("Unsupported relocation without symbol");
 
   // According to the ELF spec reference to a local symbol from outside
   // the group are not allowed. Unfortunately .eh_frame breaks that rule
@@ -743,19 +747,19 @@
 
 template ELFFile<ELF32LE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF32LE> &,
-                  const ELFFile<ELF32LE>::Elf_Rel &);
+                  const ELFFile<ELF32LE>::Elf_Rel &, uint32_t);
 
 template ELFFile<ELF32BE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF32BE> &,
-                  const ELFFile<ELF32BE>::Elf_Rel &);
+                  const ELFFile<ELF32BE>::Elf_Rel &, uint32_t);
 
 template ELFFile<ELF64LE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF64LE> &,
-                  const ELFFile<ELF64LE>::Elf_Rel &);
+                  const ELFFile<ELF64LE>::Elf_Rel &, uint32_t);
 
 template ELFFile<ELF64BE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF64BE> &,
-                  const ELFFile<ELF64BE>::Elf_Rel &);
+                  const ELFFile<ELF64BE>::Elf_Rel &, uint32_t);
 
 template bool includeInSymtab<ELF32LE>(const SymbolBody &);
 template bool includeInSymtab<ELF32BE>(const SymbolBody &);