[yaml2obj][ELF] Don't explicitly set `Binding` with STB_*

Instead, just have 3 sub-lists, one for each of
{STB_LOCAL,STB_GLOBAL,STB_WEAK}.

This allows us to be a lot more explicit w.r.t. the symbol ordering in
the object file, because if we allowed explicitly setting the STB_*
`Binding` key for the symbol, then we might have ended up having to
shuffle STB_LOCAL symbols to the front of the list, which is likely to
cause confusion and potential for error.

Also, this new approach is simpler ;)

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@184506 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/Object/ELFYAML.h b/include/llvm/Object/ELFYAML.h
index abf3693..b6c7556 100644
--- a/include/llvm/Object/ELFYAML.h
+++ b/include/llvm/Object/ELFYAML.h
@@ -40,7 +40,6 @@
 LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_SHT)
 // Just use 64, since it can hold 32-bit values too.
 LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_SHF)
-LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STB)
 LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STT)
 
 // For now, hardcode 64 bits everywhere that 32 or 64 would be needed
@@ -55,12 +54,16 @@
 };
 struct Symbol {
   StringRef Name;
-  ELF_STB Binding;
   ELF_STT Type;
   StringRef Section;
   llvm::yaml::Hex64 Value;
   llvm::yaml::Hex64 Size;
 };
+struct LocalGlobalWeakSymbols {
+  std::vector<Symbol> Local;
+  std::vector<Symbol> Global;
+  std::vector<Symbol> Weak;
+};
 struct Section {
   StringRef Name;
   ELF_SHT Type;
@@ -70,7 +73,7 @@
   StringRef Link;
   llvm::yaml::Hex64 AddressAlign;
   // For SHT_SYMTAB; should be empty otherwise.
-  std::vector<Symbol> Symbols;
+  LocalGlobalWeakSymbols Symbols;
 };
 struct Object {
   FileHeader Header;
@@ -122,11 +125,6 @@
 };
 
 template <>
-struct ScalarEnumerationTraits<ELFYAML::ELF_STB> {
-  static void enumeration(IO &IO, ELFYAML::ELF_STB &Value);
-};
-
-template <>
 struct ScalarEnumerationTraits<ELFYAML::ELF_STT> {
   static void enumeration(IO &IO, ELFYAML::ELF_STT &Value);
 };
@@ -142,6 +140,11 @@
 };
 
 template <>
+struct MappingTraits<ELFYAML::LocalGlobalWeakSymbols> {
+  static void mapping(IO &IO, ELFYAML::LocalGlobalWeakSymbols &Symbols);
+};
+
+template <>
 struct MappingTraits<ELFYAML::Section> {
   static void mapping(IO &IO, ELFYAML::Section &Section);
 };
diff --git a/lib/Object/ELFYAML.cpp b/lib/Object/ELFYAML.cpp
index 7fa7756..107333c 100644
--- a/lib/Object/ELFYAML.cpp
+++ b/lib/Object/ELFYAML.cpp
@@ -278,15 +278,6 @@
 #undef BCase
 }
 
-void ScalarEnumerationTraits<ELFYAML::ELF_STB>::enumeration(
-    IO &IO, ELFYAML::ELF_STB &Value) {
-#define ECase(X) IO.enumCase(Value, #X, ELF::X);
-  ECase(STB_LOCAL)
-  ECase(STB_GLOBAL)
-  ECase(STB_WEAK)
-#undef ECase
-}
-
 void ScalarEnumerationTraits<ELFYAML::ELF_STT>::enumeration(
     IO &IO, ELFYAML::ELF_STT &Value) {
 #define ECase(X) IO.enumCase(Value, #X, ELF::X);
@@ -313,13 +304,19 @@
 
 void MappingTraits<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) {
   IO.mapOptional("Name", Symbol.Name, StringRef());
-  IO.mapOptional("Binding", Symbol.Binding, ELFYAML::ELF_STB(0));
   IO.mapOptional("Type", Symbol.Type, ELFYAML::ELF_STT(0));
   IO.mapOptional("Section", Symbol.Section, StringRef());
   IO.mapOptional("Value", Symbol.Value, Hex64(0));
   IO.mapOptional("Size", Symbol.Size, Hex64(0));
 }
 
+void MappingTraits<ELFYAML::LocalGlobalWeakSymbols>::mapping(
+    IO &IO, ELFYAML::LocalGlobalWeakSymbols &Symbols) {
+  IO.mapOptional("Local", Symbols.Local);
+  IO.mapOptional("Global", Symbols.Global);
+  IO.mapOptional("Weak", Symbols.Weak);
+}
+
 void MappingTraits<ELFYAML::Section>::mapping(IO &IO,
                                               ELFYAML::Section &Section) {
   IO.mapOptional("Name", Section.Name, StringRef());
diff --git a/test/Object/yaml2obj-elf-symbol-LocalGlobalWeak.yaml b/test/Object/yaml2obj-elf-symbol-LocalGlobalWeak.yaml
new file mode 100644
index 0000000..44479dc
--- /dev/null
+++ b/test/Object/yaml2obj-elf-symbol-LocalGlobalWeak.yaml
@@ -0,0 +1,39 @@
+# RUN: yaml2obj -format=elf %s | llvm-readobj -symbols - | FileCheck %s
+!ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data: ELFDATA2LSB
+  Type: ET_REL
+  Machine: EM_X86_64
+Sections:
+  - Name: .data
+    Type: SHT_PROGBITS
+    Flags: [ SHF_ALLOC, SHF_WRITE ]
+    Content: "DEADBEEF"
+  - Name: .symtab
+    Type: SHT_SYMTAB
+    Symbols:
+      Local:
+        - Name: local_symbol
+          Type: STT_OBJECT
+          Section: .data
+      Global:
+        - Name: global_symbol
+          Type: STT_OBJECT
+          Section: .data
+      Weak:
+        - Name: weak_symbol
+          Type: STT_OBJECT
+          Section: .data
+
+# CHECK: Symbol {
+# CHECK:   Name:  (0)
+# CHECK: Symbol {
+# CHECK:   Name: local_symbol
+# CHECK:   Binding: Local
+# CHECK: Symbol {
+# CHECK:   Name: global_symbol
+# CHECK:   Binding: Global
+# CHECK: Symbol {
+# CHECK:   Name: weak_symbol
+# CHECK:   Binding: Weak
diff --git a/test/Object/yaml2obj-elf-symbol-basic.yaml b/test/Object/yaml2obj-elf-symbol-basic.yaml
index 12acb7e..238348b 100644
--- a/test/Object/yaml2obj-elf-symbol-basic.yaml
+++ b/test/Object/yaml2obj-elf-symbol-basic.yaml
@@ -20,12 +20,12 @@
   - Name: .symtab
     Type: SHT_SYMTAB
     Symbols:
-    - Name: main
-      Binding: STB_GLOBAL
-      Type: STT_FUNC
-      Section: .text
-      Value: 0x1
-      Size: 2
+      Global:
+        - Name: main
+          Type: STT_FUNC
+          Section: .text
+          Value: 0x1
+          Size: 2
 
 # CHECK:      Symbols [
 # CHECK-NEXT:   Symbol {
diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp
index a8eeeea..cd6df14 100644
--- a/tools/yaml2obj/yaml2elf.cpp
+++ b/tools/yaml2obj/yaml2elf.cpp
@@ -168,37 +168,21 @@
 };
 } // end anonymous namespace
 
-// FIXME: This function is hideous. The hideous ELF type names are hideous.
-// Factor the ELF output into a class (templated on ELFT) and share some
-// typedefs.
-template <class ELFT>
-static void handleSymtabSectionHeader(
-    const ELFYAML::Section &Sec, ELFState<ELFT> &State,
-    typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) {
-
-  typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
-  // TODO: Ensure that a manually specified `Link` field is diagnosed as an
-  // error for SHT_SYMTAB.
-  SHeader.sh_link = State.getDotStrTabSecNo();
-  // TODO: Once we handle symbol binding, this should be one greater than
-  // symbol table index of the last local symbol.
-  SHeader.sh_info = 0;
-  SHeader.sh_entsize = sizeof(Elf_Sym);
-
-  std::vector<Elf_Sym> Syms;
-  {
-    // Ensure STN_UNDEF is present
-    Elf_Sym Sym;
-    zero(Sym);
-    Syms.push_back(Sym);
-  }
-  for (unsigned i = 0, e = Sec.Symbols.size(); i != e; ++i) {
-    const ELFYAML::Symbol &Sym = Sec.Symbols[i];
+// FIXME: At this point it is fairly clear that we need to refactor these
+// static functions into methods of a class sharing some typedefs. These
+// ELF type names are insane.
+template <class ELFT,
+          class Elf_Sym = typename object::ELFObjectFile<ELFT>::Elf_Sym>
+static void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
+                       ELFState<ELFT> &State, std::vector<Elf_Sym> &Syms,
+                       unsigned SymbolBinding) {
+  for (unsigned i = 0, e = Symbols.size(); i != e; ++i) {
+    const ELFYAML::Symbol &Sym = Symbols[i];
     Elf_Sym Symbol;
     zero(Symbol);
     if (!Sym.Name.empty())
       Symbol.st_name = State.getStringTable().addString(Sym.Name);
-    Symbol.setBindingAndType(Sym.Binding, Sym.Type);
+    Symbol.setBindingAndType(SymbolBinding, Sym.Type);
     unsigned Index;
     if (State.getSN2I().lookupSection(Sym.Section, Index)) {
       errs() << "error: Unknown section referenced: '" << Sym.Section
@@ -210,6 +194,31 @@
     Symbol.st_size = Sym.Size;
     Syms.push_back(Symbol);
   }
+}
+
+template <class ELFT>
+static void handleSymtabSectionHeader(
+    const ELFYAML::Section &Sec, ELFState<ELFT> &State,
+    typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) {
+
+  typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
+  // TODO: Ensure that a manually specified `Link` field is diagnosed as an
+  // error for SHT_SYMTAB.
+  SHeader.sh_link = State.getDotStrTabSecNo();
+  // One greater than symbol table index of the last local symbol.
+  SHeader.sh_info = Sec.Symbols.Local.size() + 1;
+  SHeader.sh_entsize = sizeof(Elf_Sym);
+
+  std::vector<Elf_Sym> Syms;
+  {
+    // Ensure STN_UNDEF is present
+    Elf_Sym Sym;
+    zero(Sym);
+    Syms.push_back(Sym);
+  }
+  addSymbols(Sec.Symbols.Local, State, Syms, ELF::STB_LOCAL);
+  addSymbols(Sec.Symbols.Global, State, Syms, ELF::STB_GLOBAL);
+  addSymbols(Sec.Symbols.Weak, State, Syms, ELF::STB_WEAK);
 
   ContiguousBlobAccumulator &CBA = State.getSectionContentAccum();
   SHeader.sh_offset = CBA.currentOffset();