[mach-o] binary reader and writer 

This patch adds support for converting normalized mach-o to and from binary
mach-o. It also changes WriterMachO (which previously directly wrote a 
mach-o binary given a set of Atoms) to instead do it in two steps. The first 
step uses normalizedFromAtoms() to convert Atoms to normalized mach-o, and the
second step uses writeBinary() which to generate the mach-o binary file.  

llvm-svn: 194167
diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 655f3d7..005c8f7 100644
--- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -21,9 +21,11 @@
 
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/Host.h"
 #include "llvm/Support/MachO.h"
 
 using lld::mach_o::KindHandler;
+using namespace llvm::MachO;
 
 namespace lld {
 
@@ -62,71 +64,58 @@
   return false;
 }
 
-struct ArchInfo {
-  StringRef archName;
-  MachOLinkingContext::Arch arch;
-  uint32_t cputype;
-  uint32_t cpusubtype;
-};
 
-static ArchInfo archInfos[] = {
-  { "x86_64", MachOLinkingContext::arch_x86_64, llvm::MachO::CPU_TYPE_X86_64,
-    llvm::MachO::CPU_SUBTYPE_X86_64_ALL },
-  { "i386", MachOLinkingContext::arch_x86, llvm::MachO::CPU_TYPE_I386,
-    llvm::MachO::CPU_SUBTYPE_X86_ALL },
-  { "armv6", MachOLinkingContext::arch_armv6, llvm::MachO::CPU_TYPE_ARM,
-    llvm::MachO::CPU_SUBTYPE_ARM_V6 },
-  { "armv7", MachOLinkingContext::arch_armv7, llvm::MachO::CPU_TYPE_ARM,
-    llvm::MachO::CPU_SUBTYPE_ARM_V7 },
-  { "armv7s", MachOLinkingContext::arch_armv7s, llvm::MachO::CPU_TYPE_ARM,
-    llvm::MachO::CPU_SUBTYPE_ARM_V7S },
-  { StringRef(), MachOLinkingContext::arch_unknown, 0, 0 }
+MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
+  { "x86_64", arch_x86_64, true,  CPU_TYPE_X86_64,  CPU_SUBTYPE_X86_64_ALL },
+  { "i386",   arch_x86,    true,  CPU_TYPE_I386,    CPU_SUBTYPE_X86_ALL },
+  { "ppc",    arch_ppc,    false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL },
+  { "armv6",  arch_armv6,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V6 },
+  { "armv7",  arch_armv7,  true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7 },
+  { "armv7s", arch_armv7s, true,  CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V7S },
+  { "",       arch_unknown,false, 0,                0 }
 };
 
 MachOLinkingContext::Arch
 MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) {
-  for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
-    if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype)) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype))
       return info->arch;
-    }
   }
   return arch_unknown;
 }
 
 MachOLinkingContext::Arch
 MachOLinkingContext::archFromName(StringRef archName) {
-  for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
-    if (info->archName.equals(archName)) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->archName.equals(archName))
       return info->arch;
-    }
   }
   return arch_unknown;
 }
 
 uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) {
   assert(arch != arch_unknown);
-  for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
-    if (info->arch == arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
       return info->cputype;
-    }
   }
   llvm_unreachable("Unknown arch type");
 }
 
 uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) {
   assert(arch != arch_unknown);
-  for (ArchInfo *info = archInfos; !info->archName.empty(); ++info) {
-    if (info->arch == arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch)
       return info->cpusubtype;
-    }
   }
   llvm_unreachable("Unknown arch type");
 }
 
 MachOLinkingContext::MachOLinkingContext()
-    : _outputFileType(llvm::MachO::MH_EXECUTE), _outputFileTypeStatic(false),
+    : _outputFileType(MH_EXECUTE), _outputFileTypeStatic(false),
       _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
-      _pageZeroSize(0x1000), _compatibilityVersion(0), _currentVersion(0),
+      _pageZeroSize(unspecifiedPageZeroSize), 
+      _compatibilityVersion(0), _currentVersion(0),
       _deadStrippableDylib(false), _kindHandler(nullptr) {}
 
 MachOLinkingContext::~MachOLinkingContext() {}
@@ -139,11 +128,47 @@
   return cpuSubtypeFromArch(_arch);
 }
 
+bool MachOLinkingContext::is64Bit(Arch arch) {
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return (info->cputype & CPU_ARCH_ABI64);
+    }
+  }
+  // unknown archs are not 64-bit.
+  return false;
+}
+
+bool MachOLinkingContext::isHostEndian(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return (info->littleEndian == llvm::sys::IsLittleEndianHost);
+    }
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+bool MachOLinkingContext::isBigEndian(Arch arch) {
+  assert(arch != arch_unknown);
+  for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) {
+    if (info->arch == arch) {
+      return ! info->littleEndian;
+    }
+  }
+  llvm_unreachable("Unknown arch type");
+}
+
+
+
+bool MachOLinkingContext::is64Bit() const {
+  return is64Bit(_arch);
+}
+
 bool MachOLinkingContext::outputTypeHasEntry() const {
   switch (_outputFileType) {
-  case llvm::MachO::MH_EXECUTE:
-  case llvm::MachO::MH_DYLINKER:
-  case llvm::MachO::MH_PRELOAD:
+  case MH_EXECUTE:
+  case MH_DYLINKER:
+  case MH_PRELOAD:
     return true;
   default:
     return false;
@@ -169,7 +194,7 @@
 }
 
 bool MachOLinkingContext::addEntryPointLoadCommand() const {
-  if ((_outputFileType == llvm::MachO::MH_EXECUTE) && !_outputFileTypeStatic) {
+  if ((_outputFileType == MH_EXECUTE) && !_outputFileTypeStatic) {
     return minOS("10.8", "6.0");
   }
   return false;
@@ -177,14 +202,14 @@
 
 bool MachOLinkingContext::addUnixThreadLoadCommand() const {
   switch (_outputFileType) {
-  case llvm::MachO::MH_EXECUTE:
+  case MH_EXECUTE:
     if (_outputFileTypeStatic)
       return true;
     else
       return !minOS("10.8", "6.0");
     break;
-  case llvm::MachO::MH_DYLINKER:
-  case llvm::MachO::MH_PRELOAD:
+  case MH_DYLINKER:
+  case MH_PRELOAD:
     return true;
   default:
     return false;
@@ -192,7 +217,7 @@
 }
 
 bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
-  if ((_outputFileType == llvm::MachO::MH_EXECUTE) && _entrySymbolName.empty()){
+  if ((_outputFileType == MH_EXECUTE) && _entrySymbolName.empty()){
     if (_outputFileTypeStatic) {
       _entrySymbolName = "start";
     } else {
@@ -206,24 +231,35 @@
     }
   }
 
-  if (_currentVersion && _outputFileType != llvm::MachO::MH_DYLIB) {
+  // TODO: if -arch not specified, look at arch of first .o file.
+
+  // Set default __PAGEZERO for main executables
+  if ((_outputFileType == MH_EXECUTE) && !_outputFileTypeStatic
+                                && (_pageZeroSize == unspecifiedPageZeroSize)) {
+    if (is64Bit(_arch))
+      _pageZeroSize = 0x100000000;
+    else
+      _pageZeroSize = 0x00010000;
+  }
+
+  if (_currentVersion && _outputFileType != MH_DYLIB) {
     diagnostics << "error: -current_version can only be used with dylibs\n";
     return false;
   }
 
-  if (_compatibilityVersion && _outputFileType != llvm::MachO::MH_DYLIB) {
+  if (_compatibilityVersion && _outputFileType != MH_DYLIB) {
     diagnostics
         << "error: -compatibility_version can only be used with dylibs\n";
     return false;
   }
 
-  if (_deadStrippableDylib && _outputFileType != llvm::MachO::MH_DYLIB) {
+  if (_deadStrippableDylib && _outputFileType != MH_DYLIB) {
     diagnostics
         << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n";
     return false;
   }
 
-  if (!_bundleLoader.empty() && outputFileType() != llvm::MachO::MH_BUNDLE) {
+  if (!_bundleLoader.empty() && outputFileType() != MH_BUNDLE) {
     diagnostics
         << "error: -bundle_loader can only be used with Mach-O bundles\n";
     return false;
@@ -238,8 +274,10 @@
 }
 
 void MachOLinkingContext::addPasses(PassManager &pm) {
-  pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
-  pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
+  if (outputFileType() != MH_OBJECT) {
+    pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
+    pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
+  }
   pm.add(std::unique_ptr<Pass>(new LayoutPass()));
 }