added support for symbol tables in llvm-objcopy
diff --git a/test/tools/llvm-objcopy/basic-copy.test b/test/tools/llvm-objcopy/basic-copy.test
index 64bbe7e..278cffc 100644
--- a/test/tools/llvm-objcopy/basic-copy.test
+++ b/test/tools/llvm-objcopy/basic-copy.test
@@ -27,6 +27,16 @@
 # CHECK-NEXT: Offset:
 # CHECK-NEXT: Size: 4
 
+# CHECK:      Name: .symtab
+# CHECK-NEXT: Type: SHT_SYMTAB
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+
+# CHECK:      Name: .strtab
+# CHECK-NEXT: Type: SHT_STRTAB
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: ]
+
 # CHECK:      Name: .shstrtab
 # CHECK-NEXT: Type: SHT_STRTAB
 # CHECK-NEXT: Flags [
diff --git a/test/tools/llvm-objcopy/symbol-copy.test b/test/tools/llvm-objcopy/symbol-copy.test
new file mode 100644
index 0000000..d15d911
--- /dev/null
+++ b/test/tools/llvm-objcopy/symbol-copy.test
@@ -0,0 +1,91 @@
+# RUN: yaml2obj %s > %t
+# RUN: llvm-objcopy %t %t2
+# RUN: llvm-readobj -symbols %t2 | FileCheck %s
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x0000000000000010
+    Content:         "0000000000000000"
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
+    AddressAlign:    0x0000000000000010
+    Content:         "0000000000000000"
+Symbols:
+  Global:
+    - Name:     _start
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0x1000
+      Size:     4
+    - Name:     foo
+      Type:     STT_FUNC
+      Section:  .text
+      Section:  .text
+      Value:    0x1004
+    - Name:     bar
+      Type:     STT_OBJECT
+      Section:  .data
+      Value:    0x2000
+      Size:     4
+    - Name:     baz
+      Type:     STT_OBJECT
+      Section:  .data
+      Value:    0x2004
+      Size:     4
+
+#CHECK: Symbols [
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name:  (0)
+#CHECK-NEXT:    Value: 0x0
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Local
+#CHECK-NEXT:    Type: None
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: Undefined
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: _start
+#CHECK-NEXT:    Value: 0x1000
+#CHECK-NEXT:    Size: 4
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Function
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .text
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: foo
+#CHECK-NEXT:    Value: 0x1004
+#CHECK-NEXT:    Size: 0
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Function
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .text
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: bar
+#CHECK-NEXT:    Value: 0x2000
+#CHECK-NEXT:    Size: 4
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Object
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .data
+#CHECK-NEXT:  }
+#CHECK-NEXT:  Symbol {
+#CHECK-NEXT:    Name: baz
+#CHECK-NEXT:    Value: 0x2004
+#CHECK-NEXT:    Size: 4
+#CHECK-NEXT:    Binding: Global
+#CHECK-NEXT:    Type: Object
+#CHECK-NEXT:    Other: 0
+#CHECK-NEXT:    Section: .data
diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp
index 1359fb6..6f92aa3 100644
--- a/tools/llvm-objcopy/Object.cpp
+++ b/tools/llvm-objcopy/Object.cpp
@@ -114,9 +114,11 @@
   Sym.DefinedIn = DefinedIn;
   Sym.Value = Value;
   Sym.Size = Sz;
+  Sym.Index = Symbols.size();
   auto Res = Symbols.insert(std::make_pair(Name, Sym));
   if (Res.second)
     Size += sizeof(typename ELFT::Sym);
+  SymbolNames.addString(Name);
 }
 
 template <class ELFT>
@@ -126,19 +128,27 @@
     Symbols.erase(Iter);
     Size += sizeof(ELFT::Sym);
   }
+  SymbolNames.removeString(Name);
 }
 
 template <class ELFT> void SymbolTableSection<ELFT>::finalize() {
   auto CompareBinding = [](const Symbol &a, const Symbol &b) {
     return a.Binding < b.Binding;
   };
+  auto CompareIndex = [](const Symbol &a, const Symbol &b) {
+    return a.Index < b.Index;
+  };
+  // Make sure that SymbolNames is finalized first
+  SymbolNames.finalize();
   for (auto &Entry : Symbols) {
     Entry.second.NameIndex = SymbolNames.findIndex(Entry.second.Name);
     FinalSymbols.push_back(Entry.second);
   }
   Symbol DummyLocal;
   DummyLocal.Binding = STB_LOCAL;
-  std::sort(std::begin(FinalSymbols), std::end(FinalSymbols), CompareBinding);
+  std::sort(std::begin(FinalSymbols), std::end(FinalSymbols), CompareIndex);
+  std::stable_sort(std::begin(FinalSymbols), std::end(FinalSymbols),
+                   CompareBinding);
   auto Iter = std::upper_bound(std::begin(FinalSymbols), std::end(FinalSymbols),
                                DummyLocal, CompareBinding);
   Info = std::end(FinalSymbols) - Iter;
@@ -148,14 +158,9 @@
 template <class ELFT>
 void SymbolTableSection<ELFT>::writeSection(llvm::FileOutputBuffer &Out) const {
   uint8_t *Buf = Out.getBufferStart();
+  Buf += Offset;
   typename ELFT::Sym *Sym = reinterpret_cast<typename ELFT::Sym *>(Buf);
-  Sym->st_name = 0;
-  Sym->st_value = 0;
-  Sym->st_size = 0;
-  Sym->st_info = 0;
-  Sym->st_other = 0;
-  Sym->st_shndx = SHN_UNDEF;
-  ++Sym;
+
   for(auto &Symbol : FinalSymbols) {
     Sym->st_name = Symbol.NameIndex;
     Sym->st_value = Symbol.Value;
@@ -166,6 +171,7 @@
       Sym->st_shndx = Symbol.DefinedIn->Index;
     else
       Sym->st_shndx = SHN_UNDEF;
+    ++Sym;
   }
 }
 
@@ -194,22 +200,63 @@
 }
 
 template <class ELFT>
+void Object<ELFT>::readSymbolTable(const ELFFile<ELFT> &ElfFile,
+                                   const Elf_Shdr &SymTabShdr) {
+
+  StringTableSection *StrTab =
+      dyn_cast<StringTableSection>(Sections[SymTabShdr.sh_link].get());
+
+  uint32_t SymTabIndex =
+      &SymTabShdr - unwrapOrError(ElfFile.sections()).begin();
+
+  SymbolTable = new SymbolTableSection<ELFT>(*StrTab);
+  SymbolTable->Name = unwrapOrError(ElfFile.getSectionName(&SymTabShdr));
+  SymbolTable->Index = SymTabIndex;
+  SectionNames->addString(SymbolTable->Name);
+
+  StringRef StrTabData =
+      unwrapOrError(ElfFile.getStringTableForSymtab(SymTabShdr));
+
+  for (const auto &Sym : unwrapOrError(ElfFile.symbols(&SymTabShdr))) {
+    SectionBase *DefSection = nullptr;
+    if (Sym.st_shndx != SHN_UNDEF)
+      DefSection = Sections[Sym.st_shndx].get();
+    StringRef Name = unwrapOrError(Sym.getName(StrTabData));
+    SymbolTable->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection,
+                           Sym.getValue(), Sym.st_size);
+  }
+  // Calculate where the SymbolTable belongs
+  Sections[SymTabIndex].reset(SymbolTable);
+}
+
+template <class ELFT>
+static std::unique_ptr<SectionBase> makeSection(ArrayRef<uint8_t> Data,
+                                                uint64_t Type) {
+  if (Type == SHT_STRTAB)
+    return make_unique<StringTableSection>();
+  return make_unique<Section>(Data);
+}
+
+template <class ELFT>
 void Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
   uint32_t Index = 0;
-  uint32_t SymTabIndex;
   const Elf_Shdr *SymTabShdr = nullptr;
   for (const auto &Shdr : unwrapOrError(ElfFile.sections())) {
-    if (Shdr.sh_type == SHT_STRTAB) {
+    if (Index == SectionNames->Index) {
+      Sections.emplace_back(SectionNames);
       Index++;
       continue;
     }
     if (Shdr.sh_type == SHT_SYMTAB) {
+      // Put a placeholder in Sections so that Index corrasponds to the
+      // location in the array the symbol table should go
+      Sections.emplace_back(nullptr);
       SymTabShdr = &Shdr;
-      SymTabIndex = Index++;
+      Index++;
       continue;
     }
     ArrayRef<uint8_t> Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-    SecPtr Sec = make_unique<Section>(Data);
+    SecPtr Sec = makeSection<ELFT>(Data, Shdr.sh_type);
     Sec->Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
     Sec->Type = Shdr.sh_type;
     Sec->Flags = Shdr.sh_flags;
@@ -225,37 +272,9 @@
     Sections.push_back(std::move(Sec));
   }
   // If we encountered a symbol table construct it now that we should have
-  // every single. Sections are currently in Index sorted order but there is
-  // possibly a gap from the SymTabShdr. This means we can't just index into
-  // Sections to get the st_shndx item. But we can binary search which is almost
-  // as good.
-  if (SymTabShdr) {
-    StringTable = new StringTableSection();
-    StringTable->Name = ".strtab";
-    StringTable->Index = Index;
-    SectionNames->addString(StringTable->Name);
-    Sections.emplace_back(StringTable);
-
-    SymbolTable = new SymbolTableSection<ELFT>(*StringTable);
-    SymbolTable->Name = ".symtab";
-    SymbolTable->Index = SymTabIndex;
-    SectionNames->addString(SymbolTable->Name);
-
-    StringRef StrTabData =
-        unwrapOrError(ElfFile.getStringTableForSymtab(*SymTabShdr));
-    for (const auto &Sym : unwrapOrError(ElfFile.symbols(SymTabShdr))) {
-      auto DefSectionIter = std::lower_bound(
-          std::begin(Sections), std::end(Sections), Sym.st_shndx,
-          [](const SecPtr &A, uint32_t Index) { return A->Index < Index; });
-      StringRef Name = unwrapOrError(Sym.getName(StrTabData));
-      StringTable->addString(Name);
-      SymbolTable->addSymbol(Name, Sym.getBinding(), Sym.getType(),
-                             DefSectionIter->get(), Sym.getValue(),
-                             Sym.st_size);
-    }
-
-    Sections.emplace_back(SymbolTable);
-  }
+  // every section
+  if (SymTabShdr)
+    readSymbolTable(ElfFile, *SymTabShdr);
 }
 
 template <class ELFT> size_t Object<ELFT>::totalSize() const {
@@ -276,7 +295,8 @@
   Flags = Ehdr.e_flags;
 
   SectionNames = new StringTableSection();
-  SectionNames->Name = ".shstrtab";
+  auto Shdr = unwrapOrError(ElfFile.getSection(Ehdr.e_shstrndx));
+  SectionNames->Name = unwrapOrError(ElfFile.getSectionName(Shdr));
   SectionNames->Index = Ehdr.e_shstrndx;
   SectionNames->addString(SectionNames->Name);
 
@@ -331,6 +351,7 @@
 
   // finalize SectionNames first so that we can assign name indexes.
   SectionNames->finalize();
+
   // Finally now that all offsets and indexes have been set we can finalize any
   // reamining issues.
   uint64_t Offset = SHOffset;
diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h
index 77e2656..f63f00a 100644
--- a/tools/llvm-objcopy/Object.h
+++ b/tools/llvm-objcopy/Object.h
@@ -107,28 +107,27 @@
 };
 
 struct Symbol {
+  uint8_t Binding;
+  SectionBase *DefinedIn;
+  uint32_t Index;
   llvm::StringRef Name;
   uint32_t NameIndex;
-  uint8_t Binding;
-  uint8_t Type;
-  SectionBase *DefinedIn;
-  uint64_t Value;
   uint64_t Size;
+  uint8_t Type;
+  uint64_t Value;
 };
 
 // The symbol data changes from ELFT to ELFT so we need to template it. This
 // lets us implement writeSection
 template <class ELFT> class SymbolTableSection : public SectionBase {
 private:
-  StringTableSection &SymbolNames;
-  llvm::StringMap<Symbol> Symbols;
   std::vector<Symbol> FinalSymbols;
+  llvm::StringMap<Symbol> Symbols;
+  StringTableSection &SymbolNames;
 
 public:
   SymbolTableSection(StringTableSection &SymNames) : SymbolNames(SymNames) {
     Type = llvm::ELF::SHT_SYMTAB;
-    // The initlal size is to account for the dummy symbol at index 0.
-    Size = sizeof(typename ELFT::Sym);
     Align = sizeof(typename ELFT::Word);
     EntrySize = sizeof(typename ELFT::Sym);
   }
@@ -161,6 +160,8 @@
   void assignOffsets();
   void readProgramHeaders(const llvm::object::ELFFile<ELFT> &ElfFile);
   void readSectionHeaders(const llvm::object::ELFFile<ELFT> &ElfFile);
+  void readSymbolTable(const llvm::object::ELFFile<ELFT> &ElfFile,
+                       const Elf_Shdr &SymTabShdr);
   void writeHeader(llvm::FileOutputBuffer &Out) const;
   void writeProgramHeaders(llvm::FileOutputBuffer &Out) const;
   void writeSectionData(llvm::FileOutputBuffer &Out) const;