ELF: Move Visibility, IsUsedInRegularObj and MustBeInDynSym flags to Symbol.

These are properties of a symbol name, rather than a particular instance
of a symbol in an object file. We can simplify the code by collecting these
properties in Symbol.

The MustBeInDynSym flag has been renamed ExportDynamic, as its semantics
have been changed to be the same as those of --dynamic-list and
--export-dynamic-symbol, which do not cause hidden symbols to be exported.

Differential Revision: http://reviews.llvm.org/D19400

llvm-svn: 267183
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 89c12c6..e4a7ac2 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -437,7 +437,7 @@
     // Set either EntryAddr (if S is a number) or EntrySym (otherwise).
     StringRef S = Config->Entry;
     if (S.getAsInteger(0, Config->EntryAddr))
-      Config->EntrySym = Symtab.addUndefined(S)->getSymbol();
+      Config->EntrySym = Symtab.addUndefined(S)->Backref;
   }
 
   for (std::unique_ptr<InputFile> &F : Files)
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 104411f..1c0f2f5 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -76,13 +76,13 @@
 
 static bool shouldInternalize(const SmallPtrSet<GlobalValue *, 8> &Used,
                               SymbolBody &B, GlobalValue *GV) {
-  if (B.isUsedInRegularObj())
+  if (B.Backref->IsUsedInRegularObj)
     return false;
 
   if (Used.count(GV))
     return false;
 
-  return !B.includeInDynsym();
+  return !B.Backref->includeInDynsym();
 }
 
 void BitcodeCompiler::add(BitcodeFile &F) {
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 93d12a0..a64d3f7 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -128,13 +128,10 @@
 
   // Preserve externally-visible symbols if the symbols defined by this
   // file can interrupt other ELF file's symbols at runtime.
-  if (Config->Shared || Config->ExportDynamic) {
-    for (const Symbol *S : Symtab->getSymbols()) {
-      SymbolBody *B = S->Body;
-      if (B->includeInDynsym())
-        MarkSymbol(B);
-    }
-  }
+  if (Config->Shared || Config->ExportDynamic)
+    for (const Symbol *S : Symtab->getSymbols())
+      if (S->includeInDynsym())
+        MarkSymbol(S->Body);
 
   // Preserve special sections and those which are specified in linker
   // script KEEP command.
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 1add512..efcfcb3 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -1343,7 +1343,7 @@
 }
 
 static uint8_t getSymbolBinding(SymbolBody *Body) {
-  uint8_t Visibility = Body->getVisibility();
+  uint8_t Visibility = Body->Backref->Visibility;
   if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
     return STB_LOCAL;
   if (Config->NoGnuUnique && Body->Binding == STB_GNU_UNIQUE)
@@ -1428,12 +1428,6 @@
   }
 }
 
-static uint8_t getSymbolVisibility(SymbolBody *Body) {
-  if (Body->isShared())
-    return STV_DEFAULT;
-  return Body->getVisibility();
-}
-
 template <class ELFT>
 void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
   // Write the internal symbol table contents to the output symbol table
@@ -1449,7 +1443,7 @@
     ESym->setBindingAndType(getSymbolBinding(Body), Type);
     ESym->st_size = Size;
     ESym->st_name = StrOff;
-    ESym->setVisibility(getSymbolVisibility(Body));
+    ESym->setVisibility(Body->Backref->Visibility);
     ESym->st_value = Body->getVA<ELFT>();
 
     if (const OutputSectionBase<ELFT> *OutSec = getOutputSection(Body))
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index ee75d03..7bff47d6 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -132,11 +132,6 @@
     Obj->parse(DummyGroups);
     for (SymbolBody *Body : Obj->getNonLocalSymbols()) {
       Symbol *Sym = insert(Body);
-      Sym->Body->setUsedInRegularObj();
-      if (Sym->Body->isShared())
-        Sym->Body->MustBeInDynSym = true;
-      if (Sym->Body->MustBeInDynSym)
-        Body->MustBeInDynSym = true;
       if (!Sym->Body->isUndefined() && Body->isUndefined())
         continue;
       Sym->Body = Body;
@@ -198,9 +193,9 @@
   if (Symtab.count(Name) == 0)
     return;
   StringSaver Saver(Alloc);
-  Symbol *Sym = addUndefined(Name)->getSymbol();
-  Symbol *Real = addUndefined(Saver.save("__real_" + Name))->getSymbol();
-  Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->getSymbol();
+  Symbol *Sym = addUndefined(Name)->Backref;
+  Symbol *Real = addUndefined(Saver.save("__real_" + Name))->Backref;
+  Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name))->Backref;
   Real->Body = Sym->Body;
   Sym->Body = Wrap->Body;
 }
@@ -247,8 +242,6 @@
     }
     // Found a definition for something also in an archive.
     // Ignore the archive definition.
-    if (L->isUsedInRegularObj())
-      New->setUsedInRegularObj();
     Sym->Body = New;
     return;
   }
@@ -273,6 +266,23 @@
     Sym->Body = New;
 }
 
+static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
+  if (VA == STV_DEFAULT)
+    return VB;
+  if (VB == STV_DEFAULT)
+    return VA;
+  return std::min(VA, VB);
+}
+
+static bool shouldExport(SymbolBody *B) {
+  if (Config->Shared || Config->ExportDynamic) {
+    // Export most symbols except for those that do not need to be exported.
+    return !B->CanOmitFromDynSym;
+  }
+  // Make sure we preempt DSO symbols with default visibility.
+  return B->isShared() && B->getVisibility() == STV_DEFAULT;
+}
+
 // Find an existing symbol or create and insert a new one.
 template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
   StringRef Name = New->getName();
@@ -280,12 +290,24 @@
   auto P = Symtab.insert(std::make_pair(Name, NumSyms));
   Symbol *Sym;
   if (P.second) {
-    Sym = new (Alloc) Symbol{New};
+    Sym = new (Alloc) Symbol{New, STV_DEFAULT, false, false};
     SymVector.push_back(Sym);
   } else {
     Sym = SymVector[P.first->second];
   }
-  New->setBackref(Sym);
+  New->Backref = Sym;
+
+  // Merge in the new symbol's visibility. DSO symbols do not affect visibility
+  // in the output.
+  if (!New->isShared())
+    Sym->Visibility = getMinVisibility(Sym->Visibility, New->getVisibility());
+  Sym->ExportDynamic = Sym->ExportDynamic || shouldExport(New);
+  SymbolBody::Kind K = New->kind();
+  if (K == SymbolBody::DefinedRegularKind ||
+      K == SymbolBody::DefinedCommonKind ||
+      K == SymbolBody::DefinedSyntheticKind ||
+      K == SymbolBody::UndefinedElfKind)
+    Sym->IsUsedInRegularObj = true;
   return Sym;
 }
 
@@ -309,8 +331,6 @@
 
 template <class ELFT>
 void SymbolTable<ELFT>::addMemberFile(SymbolBody *Undef, Lazy *L) {
-  if (Undef->isUsedInRegularObj())
-    L->setUsedInRegularObj();
   // Weak undefined symbols should not fetch members from archives.
   // If we were to keep old symbol we would not know that an archive member was
   // available if a strong undefined symbol shows up afterwards in the link.
@@ -319,7 +339,6 @@
   // We set UsedInRegularObj in a similar way to what is done with shared
   // symbols and copy information to reduce how many special cases are needed.
   if (Undef->isWeak()) {
-    L->setUsedInRegularObj();
     L->Binding = Undef->Binding;
     L->Type = Undef->Type;
 
@@ -345,7 +364,7 @@
     for (StringRef U : File->getUndefinedSymbols())
       if (SymbolBody *Sym = find(U))
         if (Sym->isDefined())
-          Sym->MustBeInDynSym = true;
+          Sym->Backref->ExportDynamic = true;
 }
 
 // This function process the dynamic list option by marking all the symbols
@@ -353,7 +372,7 @@
 template <class ELFT> void SymbolTable<ELFT>::scanDynamicList() {
   for (StringRef S : Config->DynamicList)
     if (SymbolBody *B = find(S))
-      B->MustBeInDynSym = true;
+      B->Backref->ExportDynamic = true;
 }
 
 template class elf::SymbolTable<ELF32LE>;
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index e6f8842..43a0cbb 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -80,7 +80,7 @@
     return 0;
   case SymbolBody::LazyArchiveKind:
   case SymbolBody::LazyObjectKind:
-    assert(Body.isUsedInRegularObj() && "lazy symbol reached writer");
+    assert(Body.Backref->IsUsedInRegularObj && "lazy symbol reached writer");
     return 0;
   case SymbolBody::DefinedBitcodeKind:
     llvm_unreachable("should have been replaced");
@@ -104,13 +104,9 @@
 }
 
 void SymbolBody::init() {
-  Kind K = kind();
-  IsUsedInRegularObj = K == DefinedRegularKind || K == DefinedCommonKind ||
-                       K == DefinedSyntheticKind || K == UndefinedElfKind;
   CanKeepUndefined = false;
-  MustBeInDynSym = false;
-  CanOmitFromDynSym = false;
   NeedsCopyOrPltAddr = false;
+  CanOmitFromDynSym = false;
 }
 
 // Returns true if a symbol can be replaced at load-time by a symbol
@@ -122,7 +118,7 @@
   if (isShared())
     return true;
 
-  if (getVisibility() != STV_DEFAULT)
+  if (Backref->Visibility != STV_DEFAULT)
     return false;
 
   if (isUndefined()) {
@@ -193,14 +189,6 @@
   return 0;
 }
 
-static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
-  if (VA == STV_DEFAULT)
-    return VB;
-  if (VB == STV_DEFAULT)
-    return VA;
-  return std::min(VA, VB);
-}
-
 static int compareCommons(DefinedCommon *A, DefinedCommon *B) {
   if (Config->WarnCommon)
     warning("multiple common of " + A->getName());
@@ -220,31 +208,6 @@
   if (L > R)
     return -Other->compare(this);
 
-  uint8_t V = getMinVisibility(getVisibility(), Other->getVisibility());
-  if (isShared() != Other->isShared()) {
-    SymbolBody *Shared = isShared() ? this : Other;
-    Shared->MustBeInDynSym = true;
-    if (Shared->getVisibility() == STV_DEFAULT &&
-        (V == STV_DEFAULT || V == STV_PROTECTED)) {
-      // We want to export all symbols that exist in the executable and are
-      // preemptable in DSOs, so that the symbols in the executable can
-      // preempt symbols in the DSO at runtime.
-      SymbolBody *NonShared = isShared() ? Other : this;
-      NonShared->MustBeInDynSym = true;
-    }
-  }
-
-  if (!isShared() && !Other->isShared()) {
-    setVisibility(V);
-    Other->setVisibility(V);
-  }
-
-  if (IsUsedInRegularObj || Other->IsUsedInRegularObj)
-    IsUsedInRegularObj = Other->IsUsedInRegularObj = true;
-
-  if (!CanOmitFromDynSym || !Other->CanOmitFromDynSym)
-    CanOmitFromDynSym = Other->CanOmitFromDynSym = false;
-
   if (L != R)
     return -1;
   if (!isDefined() || isShared() || isWeak())
@@ -358,15 +321,10 @@
 #endif
 }
 
-bool SymbolBody::includeInDynsym() const {
-  if (MustBeInDynSym)
-    return true;
-  uint8_t V = getVisibility();
-  if (V != STV_DEFAULT && V != STV_PROTECTED)
+bool Symbol::includeInDynsym() const {
+  if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
     return false;
-  if (!Config->ExportDynamic && !Config->Shared)
-    return false;
-  return !CanOmitFromDynSym;
+  return ExportDynamic || Body->isShared();
 }
 
 template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index da2ab59..3b1ceea 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -40,8 +40,27 @@
 // A real symbol object, SymbolBody, is usually accessed indirectly
 // through a Symbol. There's always one Symbol for each symbol name.
 // The resolver updates SymbolBody pointers as it resolves symbols.
+// Symbol also holds computed properties of symbol names.
 struct Symbol {
   SymbolBody *Body;
+
+  // Symbol visibility. This is the computed minimum visibility of all
+  // observed non-DSO symbols.
+  unsigned Visibility : 2;
+
+  // True if the symbol was used for linking and thus need to be added to the
+  // output file's symbol table. This is true for all symbols except for
+  // unreferenced DSO symbols and bitcode symbols that are unreferenced except
+  // by other bitcode objects.
+  unsigned IsUsedInRegularObj : 1;
+
+  // If this flag is true and the symbol has protected or default visibility, it
+  // will appear in .dynsym. This flag is set by interposable DSO symbols in
+  // executables, by most symbols in DSOs and executables built with
+  // --export-dynamic, and by dynamic lists.
+  unsigned ExportDynamic : 1;
+
+  bool includeInDynsym() const;
 };
 
 // The base class for real symbol classes.
@@ -76,7 +95,6 @@
   }
   bool isShared() const { return SymbolKind == SharedKind; }
   bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
-  bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
   bool isPreemptible() const;
 
   // Returns the symbol name.
@@ -102,8 +120,6 @@
   bool isInPlt() const { return PltIndex != -1U; }
   bool hasThunk() const { return ThunkIndex != -1U; }
 
-  void setUsedInRegularObj() { IsUsedInRegularObj = true; }
-
   template <class ELFT>
   typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const;
 
@@ -121,17 +137,13 @@
   // pointer P to a SymbolBody and are not sure whether the resolver
   // has chosen the object among other objects having the same name,
   // you can access P->Backref->Body to get the resolver's result.
-  void setBackref(Symbol *P) { Backref = P; }
   SymbolBody &repl() { return Backref ? *Backref->Body : *this; }
-  Symbol *getSymbol() const { return Backref; }
 
   // Decides which symbol should "win" in the symbol table, this or
   // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
   // they are duplicate (conflicting) symbols.
   int compare(SymbolBody *Other);
 
-  bool includeInDynsym() const;
-
 protected:
   SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
              uint8_t Type);
@@ -140,12 +152,6 @@
 
   const unsigned SymbolKind : 8;
 
-  // True if the symbol was used for linking and thus need to be
-  // added to the output file's symbol table. It is usually true,
-  // but if it is a shared symbol that were not referenced by anyone,
-  // it can be false.
-  unsigned IsUsedInRegularObj : 1;
-
 public:
   // True if this symbol can be omitted from the symbol table if nothing else
   // requires it to be there. Right now this is only used for linkonce_odr in
@@ -153,9 +159,6 @@
   // MachO's .weak_def_can_be_hidden.
   unsigned CanOmitFromDynSym : 1;
 
-  // If true, the symbol is added to .dynsym symbol table.
-  unsigned MustBeInDynSym : 1;
-
   // True if the linker has to generate a copy relocation for this shared
   // symbol or if the symbol should point to its plt entry.
   unsigned NeedsCopyOrPltAddr : 1;
@@ -173,7 +176,8 @@
   bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
   bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
   bool isFile() const { return Type == llvm::ELF::STT_FILE; }
-  void setVisibility(uint8_t V) { StOther = (StOther & ~0x3) | V; }
+
+  Symbol *Backref = nullptr;
 
 protected:
   struct Str {
@@ -184,7 +188,6 @@
     Str Name;
     uint32_t NameOffset;
   };
-  Symbol *Backref = nullptr;
 };
 
 // The base class for any defined symbols.
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 93792fe..c8b8948 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -977,8 +977,7 @@
       continue;
     S.OffsetInBss = Off;
     S.NeedsCopyOrPltAddr = true;
-    S.setUsedInRegularObj();
-    S.MustBeInDynSym = true;
+    S.Backref->IsUsedInRegularObj = true;
   }
   Out<ELFT>::RelaDyn->addReloc(
       {Target->CopyRel, Out<ELFT>::Bss, SS->OffsetInBss, false, SS, 0});
@@ -1042,7 +1041,7 @@
 }
 
 template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
-  if (!B.isUsedInRegularObj())
+  if (!B.Backref->IsUsedInRegularObj)
     return false;
 
   if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
@@ -1326,7 +1325,7 @@
     if (Out<ELFT>::SymTab)
       Out<ELFT>::SymTab->addSymbol(Body);
 
-    if (isOutputDynamic() && Body->includeInDynsym())
+    if (isOutputDynamic() && S->includeInDynsym())
       Out<ELFT>::DynSymTab->addSymbol(Body);
   }