[llvm-objcopy][MachO] Rebuild the symbol/string table in the writer

Summary: Build the string table using StringTableBuilder, reassign symbol indices, and update symbol indices in relocations to allow adding/modifying/removing symbols from the object.

Reviewers: alexshap, rupprecht, jhenderson

Reviewed By: alexshap

Subscribers: mgorny, jakehehrlich, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D63309

llvm-svn: 364000
diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
index cc0e538..ce4bc2e 100644
--- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
@@ -97,8 +97,16 @@
     S.Relocations.reserve(S.NReloc);
     for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
               RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
-         RI != RE; ++RI)
-      S.Relocations.push_back(MachOObj.getRelocation(RI->getRawDataRefImpl()));
+         RI != RE; ++RI) {
+      RelocationInfo R;
+      R.Symbol = nullptr; // We'll fill this field later.
+      R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
+      R.Scattered =
+          reinterpret_cast<MachO::scattered_relocation_info *>(&R.Info)
+              ->r_scattered;
+      S.Relocations.push_back(R);
+    }
+
     assert(S.NReloc == S.Relocations.size() &&
            "Incorrect number of relocations");
   }
@@ -157,35 +165,43 @@
   }
 }
 
-template <typename nlist_t> NListEntry constructNameList(const nlist_t &nlist) {
-  NListEntry NL;
-  NL.n_strx = nlist.n_strx;
-  NL.n_type = nlist.n_type;
-  NL.n_sect = nlist.n_sect;
-  NL.n_desc = nlist.n_desc;
-  NL.n_value = nlist.n_value;
-  return NL;
+template <typename nlist_t>
+SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
+  assert(nlist.n_strx < StrTable.size() &&
+         "n_strx exceeds the size of the string table");
+  SymbolEntry SE;
+  SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
+  SE.n_type = nlist.n_type;
+  SE.n_sect = nlist.n_sect;
+  SE.n_desc = nlist.n_desc;
+  SE.n_value = nlist.n_value;
+  return SE;
 }
 
 void MachOReader::readSymbolTable(Object &O) const {
+  StringRef StrTable = MachOObj.getStringTableData();
   for (auto Symbol : MachOObj.symbols()) {
-    NListEntry NLE =
-        MachOObj.is64Bit()
-            ? constructNameList<MachO::nlist_64>(
-                  MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
-            : constructNameList<MachO::nlist>(
-                  MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl()));
-    O.SymTable.NameList.push_back(NLE);
+    SymbolEntry SE =
+        (MachOObj.is64Bit()
+             ? constructSymbolEntry(
+                   StrTable,
+                   MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
+             : constructSymbolEntry(
+                   StrTable,
+                   MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl())));
+
+    O.SymTable.Symbols.push_back(llvm::make_unique<SymbolEntry>(SE));
   }
 }
 
-void MachOReader::readStringTable(Object &O) const {
-  StringRef Data = MachOObj.getStringTableData();
-  SmallVector<StringRef, 10> Strs;
-  Data.split(Strs, '\0');
-  O.StrTable.Strings.reserve(Strs.size());
-  for (auto S : Strs)
-    O.StrTable.Strings.push_back(S.str());
+void MachOReader::setSymbolInRelocationInfo(Object &O) const {
+  for (auto &LC : O.LoadCommands)
+    for (auto &Sec : LC.Sections)
+      for (auto &Reloc : Sec.Relocations)
+        if (!Reloc.Scattered) {
+          auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info);
+          Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum);
+        }
 }
 
 void MachOReader::readRebaseInfo(Object &O) const {
@@ -213,7 +229,7 @@
   readHeader(*Obj);
   readLoadCommands(*Obj);
   readSymbolTable(*Obj);
-  readStringTable(*Obj);
+  setSymbolInRelocationInfo(*Obj);
   readRebaseInfo(*Obj);
   readBindInfo(*Obj);
   readWeakBindInfo(*Obj);