[ObjectYAML] MachO support for endianness
This patch adds support to the macho<->yaml tools for preserving endianness in MachO structures and DWARF data.
llvm-svn: 290381
diff --git a/llvm/tools/yaml2obj/yaml2macho.cpp b/llvm/tools/yaml2obj/yaml2macho.cpp
index 3fdf3cf..a68d880 100644
--- a/llvm/tools/yaml2obj/yaml2macho.cpp
+++ b/llvm/tools/yaml2obj/yaml2macho.cpp
@@ -41,8 +41,7 @@
   Error writeLoadCommands(raw_ostream &OS);
   Error writeSectionData(raw_ostream &OS);
   Error writeLinkEditData(raw_ostream &OS);
-  Error writeDWARFData(raw_ostream &OS,
-                       std::vector<MachOYAML::Section> &Sections);
+
   void writeBindOpcodes(raw_ostream &OS,
                         std::vector<MachOYAML::BindOpcode> &BindOpcodes);
   // LinkEdit writers
@@ -85,6 +84,9 @@
   Header.flags = Obj.Header.flags;
   Header.reserved = Obj.Header.reserved;
 
+  if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
+    MachO::swapStruct(Header);
+
   auto header_size =
       is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
   OS.write((const char *)&Header, header_size);
@@ -110,16 +112,20 @@
 }
 
 template <typename StructType>
-size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
+size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS,
+                            bool IsLittleEndian) {
   return 0;
 }
 
 template <>
 size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC,
-                                                    raw_ostream &OS) {
+                                                    raw_ostream &OS,
+                                                    bool IsLittleEndian) {
   size_t BytesWritten = 0;
   for (const auto &Sec : LC.Sections) {
     auto TempSec = constructSection<MachO::section>(Sec);
+    if (IsLittleEndian != sys::IsLittleEndianHost)
+      MachO::swapStruct(TempSec);
     OS.write(reinterpret_cast<const char *>(&(TempSec)),
              sizeof(MachO::section));
     BytesWritten += sizeof(MachO::section);
@@ -128,13 +134,14 @@
 }
 
 template <>
-size_t
-writeLoadCommandData<MachO::segment_command_64>(MachOYAML::LoadCommand &LC,
-                                                raw_ostream &OS) {
+size_t writeLoadCommandData<MachO::segment_command_64>(
+    MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
   size_t BytesWritten = 0;
   for (const auto &Sec : LC.Sections) {
     auto TempSec = constructSection<MachO::section_64>(Sec);
     TempSec.reserved3 = Sec.reserved3;
+    if (IsLittleEndian != sys::IsLittleEndianHost)
+      MachO::swapStruct(TempSec);
     OS.write(reinterpret_cast<const char *>(&(TempSec)),
              sizeof(MachO::section_64));
     BytesWritten += sizeof(MachO::section_64);
@@ -153,19 +160,22 @@
 
 template <>
 size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
-                                                  raw_ostream &OS) {
+                                                  raw_ostream &OS,
+                                                  bool IsLittleEndian) {
   return writePayloadString(LC, OS);
 }
 
 template <>
 size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
-                                                     raw_ostream &OS) {
+                                                     raw_ostream &OS,
+                                                     bool IsLittleEndian) {
   return writePayloadString(LC, OS);
 }
 
 template <>
 size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
-                                                  raw_ostream &OS) {
+                                                  raw_ostream &OS,
+                                                  bool IsLittleEndian) {
   return writePayloadString(LC, OS);
 }
 
@@ -190,20 +200,28 @@
 Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
   for (auto &LC : Obj.LoadCommands) {
     size_t BytesWritten = 0;
+    llvm::MachO::macho_load_command Data = LC.Data;
+
 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \
   case MachO::LCName:                                                          \
-    OS.write(reinterpret_cast<const char *>(&(LC.Data.LCStruct##_data)),       \
+    if (Obj.IsLittleEndian != sys::IsLittleEndianHost)                         \
+      MachO::swapStruct(Data.LCStruct##_data);                                 \
+    OS.write(reinterpret_cast<const char *>(&(Data.LCStruct##_data)),          \
              sizeof(MachO::LCStruct));                                         \
     BytesWritten = sizeof(MachO::LCStruct);                                    \
-    BytesWritten += writeLoadCommandData<MachO::LCStruct>(LC, OS);             \
+    BytesWritten +=                                                            \
+        writeLoadCommandData<MachO::LCStruct>(LC, OS, Obj.IsLittleEndian);     \
     break;
 
     switch (LC.Data.load_command_data.cmd) {
     default:
-      OS.write(reinterpret_cast<const char *>(&(LC.Data.load_command_data)),
+      if (Obj.IsLittleEndian != sys::IsLittleEndianHost)
+        MachO::swapStruct(Data.load_command_data);
+      OS.write(reinterpret_cast<const char *>(&(Data.load_command_data)),
                sizeof(MachO::load_command));
       BytesWritten = sizeof(MachO::load_command);
-      BytesWritten += writeLoadCommandData<MachO::load_command>(LC, OS);
+      BytesWritten +=
+          writeLoadCommandData<MachO::load_command>(LC, OS, Obj.IsLittleEndian);
       break;
 #include "llvm/Support/MachO.def"
     }
@@ -230,41 +248,38 @@
 }
 
 Error MachOWriter::writeSectionData(raw_ostream &OS) {
+  bool FoundLinkEditSeg = false;
   for (auto &LC : Obj.LoadCommands) {
     switch (LC.Data.load_command_data.cmd) {
     case MachO::LC_SEGMENT:
     case MachO::LC_SEGMENT_64:
-      auto currOffset = OS.tell() - fileStart;
-      auto segname = LC.Data.segment_command_data.segname;
       uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
                                 : LC.Data.segment_command_data.fileoff;
-
-      if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) {
+      if (0 == strncmp(&LC.Data.segment_command_data.segname[0], "__LINKEDIT", 16)) {
+        FoundLinkEditSeg = true;
         if (auto Err = writeLinkEditData(OS))
           return Err;
-      } else if (0 == strncmp(&segname[0], "__DWARF", 16)) {
-        if (auto Err = writeDWARFData(OS, LC.Sections))
-          return Err;
-      } else {
+      }
+      for (auto &Sec : LC.Sections) {
+        ZeroToOffset(OS, Sec.offset);
         // Zero Fill any data between the end of the last thing we wrote and the
         // start of this section.
-        if (currOffset < segOff) {
-          ZeroFillBytes(OS, segOff - currOffset);
-        }
-
-        for (auto &Sec : LC.Sections) {
-          // Zero Fill any data between the end of the last thing we wrote and
-          // the
-          // start of this section.
-          assert(
-              (OS.tell() - fileStart <= Sec.offset ||
-               Sec.offset == (uint32_t)0) &&
-              "Wrote too much data somewhere, section offsets don't line up.");
-          currOffset = OS.tell() - fileStart;
-          if (currOffset < Sec.offset) {
-            ZeroFillBytes(OS, Sec.offset - currOffset);
+        assert((OS.tell() - fileStart <= Sec.offset ||
+                Sec.offset == (uint32_t)0) &&
+               "Wrote too much data somewhere, section offsets don't line up.");
+        if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) {
+          if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) {
+            yaml2debug_str(OS, Obj.DWARF);
+          } else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) {
+            yaml2debug_abbrev(OS, Obj.DWARF);
+          } else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) {
+            yaml2debug_aranges(OS, Obj.DWARF);
+          } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) {
+            yaml2pubsection(OS, Obj.DWARF.PubNames, Obj.IsLittleEndian);
+          } else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) {
+            yaml2pubsection(OS, Obj.DWARF.PubTypes, Obj.IsLittleEndian);
           }
-
+        } else {
           // Fills section data with 0xDEADBEEF
           Fill(OS, Sec.size, 0xDEADBEEFu);
         }
@@ -275,6 +290,12 @@
       break;
     }
   }
+  // Old PPC Object Files didn't have __LINKEDIT segments, the data was just
+  // stuck at the end of the file.
+  if (!FoundLinkEditSeg) {
+    if (auto Err = writeLinkEditData(OS))
+      return Err;
+  }
   return Error::success();
 }
 
@@ -328,13 +349,17 @@
 }
 
 template <typename NListType>
-void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS) {
+void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS,
+                     bool IsLittleEndian) {
   NListType ListEntry;
   ListEntry.n_strx = NLE.n_strx;
   ListEntry.n_type = NLE.n_type;
   ListEntry.n_sect = NLE.n_sect;
   ListEntry.n_desc = NLE.n_desc;
   ListEntry.n_value = NLE.n_value;
+
+  if (sys::IsBigEndianHost)
+    MachO::swapStruct(ListEntry);
   OS.write(reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
 }
 
@@ -384,25 +409,6 @@
   return Error::success();
 }
 
-Error MachOWriter::writeDWARFData(raw_ostream &OS,
-                                  std::vector<MachOYAML::Section> &Sections) {
-  for (auto Section : Sections) {
-    ZeroToOffset(OS, Section.offset);
-    if (0 == strncmp(&Section.sectname[0], "__debug_str", 16)) {
-      yaml2debug_str(OS, Obj.DWARF);
-    } else if (0 == strncmp(&Section.sectname[0], "__debug_abbrev", 16)) {
-      yaml2debug_abbrev(OS, Obj.DWARF);
-    } else if (0 == strncmp(&Section.sectname[0], "__debug_aranges", 16)) {
-      yaml2debug_aranges(OS, Obj.DWARF);
-    } else if (0 == strncmp(&Section.sectname[0], "__debug_pubnames", 16)) {
-      yaml2pubsection(OS, Obj.DWARF.PubNames);
-    } else if (0 == strncmp(&Section.sectname[0], "__debug_pubtypes", 16)) {
-      yaml2pubsection(OS, Obj.DWARF.PubTypes);
-    }
-  }
-  return Error::success();
-}
-
 Error MachOWriter::writeRebaseOpcodes(raw_ostream &OS) {
   MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
 
@@ -434,9 +440,9 @@
 Error MachOWriter::writeNameList(raw_ostream &OS) {
   for (auto NLE : Obj.LinkEdit.NameList) {
     if (is64Bit)
-      writeNListEntry<MachO::nlist_64>(NLE, OS);
+      writeNListEntry<MachO::nlist_64>(NLE, OS, Obj.IsLittleEndian);
     else
-      writeNListEntry<MachO::nlist>(NLE, OS);
+      writeNListEntry<MachO::nlist>(NLE, OS, Obj.IsLittleEndian);
   }
   return Error::success();
 }