Add support for weak symbols.

llvm-svn: 244636
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 9dcd2fa..3a11967 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -75,9 +75,17 @@
   ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
   error(NameOrErr.getError());
   StringRef Name = *NameOrErr;
-  if (Sym->isUndefined())
-    return new (Alloc) Undefined(Name);
-  return new (Alloc) DefinedRegular<ELFT>(Name);
+  switch (Sym->getBinding()) {
+  default:
+    error("unexpected binding");
+  case STB_GLOBAL:
+    if (Sym->isUndefined())
+      return new (Alloc) Undefined(Name);
+    return new (Alloc) DefinedRegular<ELFT>(Name);
+  case STB_WEAK:
+    // FIXME: add support for weak undefined
+    return new (Alloc) DefinedWeak<ELFT>(Name);
+  }
 }
 
 namespace lld {
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 32bcf8e..0964437 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -21,6 +21,10 @@
 DefinedRegular<ELFT>::DefinedRegular(StringRef Name)
     : Defined(DefinedRegularKind, Name) {}
 
+template <class ELFT>
+DefinedWeak<ELFT>::DefinedWeak(StringRef Name)
+    : Defined(DefinedWeakKind, Name) {}
+
 // Returns 1, 0 or -1 if this symbol should take precedence
 // over the Other, tie or lose, respectively.
 int SymbolBody::compare(SymbolBody *Other) {
@@ -32,16 +36,14 @@
     return -Other->compare(this);
 
   // First handle comparisons between two different kinds.
-  if (LK != RK) {
-    assert(LK == DefinedRegularKind);
-    assert(RK == UndefinedKind);
+  if (LK != RK)
     return 1;
-  }
 
   // Now handle the case where the kinds are the same.
   switch (LK) {
   case DefinedRegularKind:
     return 0;
+  case DefinedWeakKind:
   case UndefinedKind:
     return 1;
   }
@@ -54,5 +56,10 @@
 template class DefinedRegular<llvm::object::ELF32BE>;
 template class DefinedRegular<llvm::object::ELF64LE>;
 template class DefinedRegular<llvm::object::ELF64BE>;
+
+template class DefinedWeak<llvm::object::ELF32LE>;
+template class DefinedWeak<llvm::object::ELF32BE>;
+template class DefinedWeak<llvm::object::ELF64LE>;
+template class DefinedWeak<llvm::object::ELF64BE>;
 }
 }
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 197a30c..18e31da 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -37,8 +37,9 @@
   enum Kind {
     DefinedFirst = 0,
     DefinedRegularKind = 0,
-    DefinedLast = 0,
-    UndefinedKind = 1,
+    DefinedWeakKind = 1,
+    DefinedLast = 1,
+    UndefinedKind = 2
   };
 
   Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -92,6 +93,15 @@
   }
 };
 
+template <class ELFT> class DefinedWeak : public Defined {
+public:
+  DefinedWeak(StringRef Name);
+
+  static bool classof(const SymbolBody *S) {
+    return S->kind() == DefinedWeakKind;
+  }
+};
+
 // Undefined symbols.
 class Undefined : public SymbolBody {
 public:
diff --git a/lld/test/elf2/Inputs/invalid-binding.elf b/lld/test/elf2/Inputs/invalid-binding.elf
new file mode 100644
index 0000000..61b5af9
--- /dev/null
+++ b/lld/test/elf2/Inputs/invalid-binding.elf
Binary files differ
diff --git a/lld/test/elf2/Inputs/local.s b/lld/test/elf2/Inputs/local.s
deleted file mode 100644
index a5c4ffc..0000000
--- a/lld/test/elf2/Inputs/local.s
+++ /dev/null
@@ -1 +0,0 @@
-local:
diff --git a/lld/test/elf2/Inputs/resolution.s b/lld/test/elf2/Inputs/resolution.s
new file mode 100644
index 0000000..e3ab048
--- /dev/null
+++ b/lld/test/elf2/Inputs/resolution.s
@@ -0,0 +1,10 @@
+local:
+
+.weak foo
+foo:
+
+.weak _start
+_start:
+
+.weak bar
+bar:
diff --git a/lld/test/elf2/invalid-elf.test b/lld/test/elf2/invalid-elf.test
index 95fd671..5b2bea3 100644
--- a/lld/test/elf2/invalid-elf.test
+++ b/lld/test/elf2/invalid-elf.test
@@ -9,3 +9,7 @@
 RUN: not lld -flavor gnu2 %p/Inputs/invalid-symtab-sh_info.elf -o %t2 2>&1 | \
 RUN:   FileCheck --check-prefix=INVALID-SYMTAB-SHINFO %s
 INVALID-SYMTAB-SHINFO: Invalid sh_info in symbol table
+
+RUN: not lld -flavor gnu2 %p/Inputs/invalid-binding.elf -o %t2 2>&1 | \
+RUN:   FileCheck --check-prefix=INVALID-BINDING %s
+INVALID-BINDING: unexpected binding
diff --git a/lld/test/elf2/local.s b/lld/test/elf2/resolution.s
similarity index 81%
rename from lld/test/elf2/local.s
rename to lld/test/elf2/resolution.s
index 295ff61..a49c7d5 100644
--- a/lld/test/elf2/local.s
+++ b/lld/test/elf2/resolution.s
@@ -1,5 +1,5 @@
 // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t
-// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/local.s -o %t2
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/resolution.s -o %t2
 // RUN: lld -flavor gnu2 %t %t2 -o %t3
 // REQUIRES: x86
 
@@ -8,3 +8,8 @@
         nop
 
 local:
+
+.weak foo
+foo:
+
+.long bar