Compute value of local symbol with getVA.

llvm-svn: 263225
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index b780a99..e2fa005 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -29,52 +29,81 @@
 using namespace lld::elf;
 
 template <class ELFT>
-typename ELFFile<ELFT>::uintX_t SymbolBody::getVA() const {
-  switch (kind()) {
-  case DefinedSyntheticKind: {
-    auto *D = cast<DefinedSynthetic<ELFT>>(this);
-    return D->Section.getVA() + D->Value;
+static typename ELFFile<ELFT>::uintX_t
+getSymVA(const SymbolBody &Body, typename ELFFile<ELFT>::uintX_t &Addend) {
+  typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
+  typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+
+  switch (Body.kind()) {
+  case SymbolBody::DefinedSyntheticKind: {
+    auto &D = cast<DefinedSynthetic<ELFT>>(Body);
+    return D.Section.getVA() + D.Value;
   }
-  case DefinedRegularKind: {
-    auto *D = cast<DefinedRegular<ELFT>>(this);
-    InputSectionBase<ELFT> *SC = D->Section;
+  case SymbolBody::DefinedRegularKind: {
+    auto &D = cast<DefinedRegular<ELFT>>(Body);
+    InputSectionBase<ELFT> *SC = D.Section;
 
     // This is an absolute symbol.
     if (!SC)
-      return D->Sym.st_value;
+      return D.Sym.st_value;
     assert(SC->Live);
 
-    if (D->Sym.getType() == STT_TLS)
-      return SC->OutSec->getVA() + SC->getOffset(D->Sym) -
+    if (D.Sym.getType() == STT_TLS)
+      return SC->OutSec->getVA() + SC->getOffset(D.Sym) -
              Out<ELFT>::TlsPhdr->p_vaddr;
-    return SC->OutSec->getVA() + SC->getOffset(D->Sym);
+    return SC->OutSec->getVA() + SC->getOffset(D.Sym);
   }
-  case DefinedCommonKind:
-    return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(this)->OffsetInBss;
-  case SharedKind: {
-    auto *SS = cast<SharedSymbol<ELFT>>(this);
-    if (!SS->NeedsCopyOrPltAddr)
+  case SymbolBody::DefinedCommonKind:
+    return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss;
+  case SymbolBody::SharedKind: {
+    auto &SS = cast<SharedSymbol<ELFT>>(Body);
+    if (!SS.NeedsCopyOrPltAddr)
       return 0;
-    if (SS->IsFunc)
-      return getPltVA<ELFT>();
+    if (SS.IsFunc)
+      return Body.getPltVA<ELFT>();
     else
-      return Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
+      return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
   }
-  case UndefinedElfKind:
-  case UndefinedKind:
+  case SymbolBody::UndefinedElfKind:
+  case SymbolBody::UndefinedKind:
     return 0;
-  case LazyKind:
-    assert(isUsedInRegularObj() && "Lazy symbol reached writer");
+  case SymbolBody::LazyKind:
+    assert(Body.isUsedInRegularObj() && "Lazy symbol reached writer");
     return 0;
-  case DefinedBitcodeKind:
+  case SymbolBody::DefinedBitcodeKind:
     llvm_unreachable("Should have been replaced");
-  case DefinedLocalKind:
-    llvm_unreachable("Should not be used");
+  case SymbolBody::DefinedLocalKind: {
+    auto &L = cast<LocalSymbol<ELFT>>(Body);
+    InputSectionBase<ELFT> *SC = L.Section;
+
+    // According to the ELF spec reference to a local symbol from outside the
+    // group are not allowed. Unfortunately .eh_frame breaks that rule and must
+    // be treated specially. For now we just replace the symbol with 0.
+    if (SC == InputSection<ELFT>::Discarded || !SC->Live)
+      return 0;
+
+    const Elf_Sym &Sym = L.Sym;
+    uintX_t Offset = Sym.st_value;
+    if (Sym.getType() == STT_TLS)
+      return (SC->OutSec->getVA() + SC->getOffset(Sym) + Addend) -
+             Out<ELFT>::TlsPhdr->p_vaddr;
+    if (Sym.getType() == STT_SECTION) {
+      Offset += Addend;
+      Addend = 0;
+    }
+    return SC->OutSec->getVA() + SC->getOffset(Offset);
+  }
   }
   llvm_unreachable("Invalid symbol kind");
 }
 
 template <class ELFT>
+typename ELFFile<ELFT>::uintX_t
+SymbolBody::getVA(typename ELFFile<ELFT>::uintX_t Addend) const {
+  return getSymVA<ELFT>(*this, Addend) + Addend;
+}
+
+template <class ELFT>
 typename ELFFile<ELFT>::uintX_t SymbolBody::getGotVA() const {
   return Out<ELFT>::Got->getVA() +
          (Out<ELFT>::Got->getMipsLocalEntriesNum() + GotIndex) *
@@ -231,10 +260,10 @@
 #endif
 }
 
-template uint32_t SymbolBody::template getVA<ELF32LE>() const;
-template uint32_t SymbolBody::template getVA<ELF32BE>() const;
-template uint64_t SymbolBody::template getVA<ELF64LE>() const;
-template uint64_t SymbolBody::template getVA<ELF64BE>() const;
+template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
+template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
+template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
+template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
 
 template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
 template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;