Change the type hierarchy for undefined symbols.
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 6 Apr 2016 13:22:41 +0000 (13:22 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 6 Apr 2016 13:22:41 +0000 (13:22 +0000)
We have to differentiate undefined symbols from bitcode and undefined
symbols from other sources.

Undefined symbols from bitcode should not inhibit the symbol being
internalized. Undefined symbols from other sources should.

llvm-svn: 265536

lld/ELF/InputFiles.cpp
lld/ELF/OutputSections.cpp
lld/ELF/SymbolTable.cpp
lld/ELF/SymbolTable.h
lld/ELF/Symbols.cpp
lld/ELF/Symbols.h
lld/ELF/Writer.cpp
lld/test/ELF/lto/Inputs/internalize-undef.ll [new file with mode: 0644]
lld/test/ELF/lto/internalize-undef.ll [new file with mode: 0644]

index 4d11f35..3d23fde 100644 (file)
@@ -473,7 +473,7 @@ BitcodeFile::createSymbolBody(const DenseSet<const Comdat *> &KeptComdats,
   uint32_t Flags = Sym.getFlags();
   bool IsWeak = Flags & BasicSymbolRef::SF_Weak;
   if (Flags & BasicSymbolRef::SF_Undefined) {
-    Body = new (Alloc) Undefined(NameRef, IsWeak, Visibility, false);
+    Body = new (Alloc) UndefinedBitcode(NameRef, IsWeak, Visibility);
   } else if (Flags & BasicSymbolRef::SF_Common) {
     const DataLayout &DL = M.getDataLayout();
     uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
index 6a2e493..18d1ed4 100644 (file)
@@ -1501,7 +1501,7 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
       return Out<ELFT>::Bss;
     break;
   case SymbolBody::UndefinedElfKind:
-  case SymbolBody::UndefinedKind:
+  case SymbolBody::UndefinedBitcodeKind:
   case SymbolBody::LazyKind:
     break;
   case SymbolBody::DefinedBitcodeKind:
index 1cc9a30..ba91b10 100644 (file)
@@ -122,7 +122,8 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLtoObject() {
 // Add an undefined symbol.
 template <class ELFT>
 SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
-  auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false);
+  auto *Sym = new (Alloc)
+      UndefinedElf<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0, false);
   resolve(Sym);
   return Sym;
 }
@@ -131,7 +132,8 @@ SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
 // doesn't have to be resolved, thus "opt" (optional).
 template <class ELFT>
 SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
-  auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true);
+  auto *Sym = new (Alloc)
+      UndefinedElf<ELFT>(Name, STB_GLOBAL, STV_HIDDEN, /*Type*/ 0, true);
   resolve(Sym);
   return Sym;
 }
@@ -222,8 +224,8 @@ template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
   SymbolBody *Existing = Sym->Body;
 
   if (auto *L = dyn_cast<Lazy>(Existing)) {
-    if (auto *Undef = dyn_cast<Undefined>(New)) {
-      addMemberFile(Undef, L);
+    if (New->isUndefined()) {
+      addMemberFile(New, L);
       return;
     }
     // Found a definition for something also in an archive.
@@ -273,16 +275,17 @@ template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
 
 template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) {
   Symbol *Sym = insert(L);
-  if (Sym->Body == L)
+  SymbolBody *Cur = Sym->Body;
+  if (Cur == L)
     return;
-  if (auto *Undef = dyn_cast<Undefined>(Sym->Body)) {
+  if (Cur->isUndefined()) {
     Sym->Body = L;
-    addMemberFile(Undef, L);
+    addMemberFile(Cur, L);
   }
 }
 
 template <class ELFT>
-void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) {
+void SymbolTable<ELFT>::addMemberFile(SymbolBody *Undef, Lazy *L) {
   if (Undef->isUsedInRegularObj())
     L->setUsedInRegularObj();
   // Weak undefined symbols should not fetch members from archives.
index ea2ea94..b80e7df 100644 (file)
@@ -19,7 +19,6 @@ namespace elf {
 class Lazy;
 template <class ELFT> class OutputSectionBase;
 struct Symbol;
-class Undefined;
 
 // SymbolTable is a bucket of all known symbols, including defined,
 // undefined, or lazy symbols (the last one is symbols in archive
@@ -68,7 +67,7 @@ public:
 private:
   Symbol *insert(SymbolBody *New);
   void addLazy(Lazy *New);
-  void addMemberFile(Undefined *Undef, Lazy *L);
+  void addMemberFile(SymbolBody *Undef, Lazy *L);
   void resolve(SymbolBody *Body);
   std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
 
index 78fabc8..add7546 100644 (file)
@@ -76,7 +76,7 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
     return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
   }
   case SymbolBody::UndefinedElfKind:
-  case SymbolBody::UndefinedKind:
+  case SymbolBody::UndefinedBitcodeKind:
     return 0;
   case SymbolBody::LazyKind:
     assert(Body.isUsedInRegularObj() && "lazy symbol reached writer");
@@ -91,8 +91,22 @@ SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
                        uint8_t Type)
     : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
       Type(Type), Binding(STB_LOCAL), StOther(StOther), NameOffset(NameOffset) {
-  IsUsedInRegularObj =
-      K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
+  init();
+}
+
+SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
+                       uint8_t Type)
+    : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
+      Type(Type), Binding(Binding), StOther(StOther),
+      Name({Name.data(), Name.size()}) {
+  assert(!isLocal());
+  init();
+}
+
+void SymbolBody::init() {
+  Kind K = kind();
+  IsUsedInRegularObj = K == DefinedRegularKind || K == DefinedCommonKind ||
+                       K == DefinedSyntheticKind || K == UndefinedElfKind;
 }
 
 // Returns true if a symbol can be replaced at load-time by a symbol
@@ -239,31 +253,27 @@ bool DefinedBitcode::classof(const SymbolBody *S) {
   return S->kind() == DefinedBitcodeKind;
 }
 
-Undefined::Undefined(SymbolBody::Kind K, StringRef N, uint8_t Binding,
-                     uint8_t Other, uint8_t Type)
-    : SymbolBody(K, N, Binding, Other, Type), CanKeepUndefined(false) {}
-
-Undefined::Undefined(SymbolBody::Kind K, uint32_t NameOffset,
-                     uint8_t StOther, uint8_t Type)
-    : SymbolBody(K, NameOffset, StOther, Type), CanKeepUndefined(false) {}
-
-Undefined::Undefined(StringRef N, bool IsWeak, uint8_t StOther,
-                     bool CanKeepUndefined)
-    : Undefined(SymbolBody::UndefinedKind, N, IsWeak ? STB_WEAK : STB_GLOBAL,
-                StOther, 0 /* Type */) {
-  this->CanKeepUndefined = CanKeepUndefined;
-}
+UndefinedBitcode::UndefinedBitcode(StringRef N, bool IsWeak, uint8_t StOther)
+    : SymbolBody(SymbolBody::UndefinedBitcodeKind, N,
+                 IsWeak ? STB_WEAK : STB_GLOBAL, StOther, 0 /* Type */) {}
 
 template <typename ELFT>
 UndefinedElf<ELFT>::UndefinedElf(StringRef N, const Elf_Sym &Sym)
-    : Undefined(SymbolBody::UndefinedElfKind, N, Sym.getBinding(), Sym.st_other,
-                Sym.getType()),
+    : SymbolBody(SymbolBody::UndefinedElfKind, N, Sym.getBinding(),
+                 Sym.st_other, Sym.getType()),
       Size(Sym.st_size) {}
 
 template <typename ELFT>
+UndefinedElf<ELFT>::UndefinedElf(StringRef Name, uint8_t Binding,
+                                 uint8_t StOther, uint8_t Type,
+                                 bool CanKeepUndefined)
+    : SymbolBody(SymbolBody::UndefinedElfKind, Name, Binding, StOther, Type),
+      CanKeepUndefined(CanKeepUndefined) {}
+
+template <typename ELFT>
 UndefinedElf<ELFT>::UndefinedElf(const Elf_Sym &Sym)
-    : Undefined(SymbolBody::UndefinedElfKind, Sym.st_name, Sym.st_other,
-                Sym.getType()),
+    : SymbolBody(SymbolBody::UndefinedElfKind, Sym.st_name, Sym.st_other,
+                 Sym.getType()),
       Size(Sym.st_size) {
   assert(Sym.getBinding() == STB_LOCAL);
 }
index 72d7d81..afd8743 100644 (file)
@@ -46,6 +46,8 @@ struct Symbol {
 
 // The base class for real symbol classes.
 class SymbolBody {
+  void init();
+
 public:
   enum Kind {
     DefinedFirst,
@@ -56,7 +58,7 @@ public:
     DefinedSyntheticKind,
     DefinedLast = DefinedSyntheticKind,
     UndefinedElfKind,
-    UndefinedKind,
+    UndefinedBitcodeKind,
     LazyKind
   };
 
@@ -64,7 +66,7 @@ public:
 
   bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
   bool isUndefined() const {
-    return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind;
+    return SymbolKind == UndefinedBitcodeKind || SymbolKind == UndefinedElfKind;
   }
   bool isDefined() const { return SymbolKind <= DefinedLast; }
   bool isCommon() const { return SymbolKind == DefinedCommonKind; }
@@ -125,14 +127,7 @@ public:
 
 protected:
   SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
-             uint8_t Type)
-      : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
-        Type(Type), Binding(Binding), StOther(StOther),
-        Name({Name.data(), Name.size()}) {
-    assert(!isLocal());
-    IsUsedInRegularObj =
-        K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
-  }
+             uint8_t Type);
 
   SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
 
@@ -282,31 +277,27 @@ public:
   const OutputSectionBase<ELFT> &Section;
 };
 
-// Undefined symbol.
-class Undefined : public SymbolBody {
-  typedef SymbolBody::Kind Kind;
-  bool CanKeepUndefined;
-
-protected:
-  Undefined(Kind K, StringRef N, uint8_t Binding, uint8_t StOther,
-            uint8_t Type);
-  Undefined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
-
+class UndefinedBitcode : public SymbolBody {
 public:
-  Undefined(StringRef N, bool IsWeak, uint8_t StOther, bool CanKeepUndefined);
+  UndefinedBitcode(StringRef N, bool IsWeak, uint8_t StOther);
 
-  static bool classof(const SymbolBody *S) { return S->isUndefined(); }
-
-  bool canKeepUndefined() const { return CanKeepUndefined; }
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == UndefinedBitcodeKind;
+  }
 };
 
-template <class ELFT> class UndefinedElf : public Undefined {
+template <class ELFT> class UndefinedElf : public SymbolBody {
   typedef typename ELFT::uint uintX_t;
   typedef typename ELFT::Sym Elf_Sym;
+  bool CanKeepUndefined = false;
 
 public:
   UndefinedElf(StringRef N, const Elf_Sym &Sym);
   UndefinedElf(const Elf_Sym &Sym);
+  UndefinedElf(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type,
+               bool CanKeepUndefined);
+
+  bool canKeepUndefined() const { return CanKeepUndefined; }
 
   uintX_t Size;
 
index e3601f4..27a1e0f 100644 (file)
@@ -1069,9 +1069,11 @@ template <class ELFT> void Writer<ELFT>::createSections() {
   std::vector<DefinedCommon *> CommonSymbols;
   for (auto &P : Symtab.getSymbols()) {
     SymbolBody *Body = P.second->Body;
-    if (auto *U = dyn_cast<Undefined>(Body))
-      if (!U->isWeak() && !U->canKeepUndefined())
+    if (Body->isUndefined() && !Body->isWeak()) {
+      auto *U = dyn_cast<UndefinedElf<ELFT>>(Body);
+      if (!U || !U->canKeepUndefined())
         reportUndefined<ELFT>(Symtab, Body);
+    }
 
     if (auto *C = dyn_cast<DefinedCommon>(Body))
       CommonSymbols.push_back(C);
diff --git a/lld/test/ELF/lto/Inputs/internalize-undef.ll b/lld/test/ELF/lto/Inputs/internalize-undef.ll
new file mode 100644 (file)
index 0000000..71c1e4f
--- /dev/null
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+  ret void
+}
diff --git a/lld/test/ELF/lto/internalize-undef.ll b/lld/test/ELF/lto/internalize-undef.ll
new file mode 100644 (file)
index 0000000..5d74c31
--- /dev/null
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
+; RUN: llvm-dis < %t.lto.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f()
+define void @_start() {
+  call void @f()
+  ret void
+}
+
+; CHECK: define internal void @f()