[lld] r194167 - [mach-o] binary reader and writer

Nick Kledzik kledzik at apple.com
Wed Nov 6 13:36:56 PST 2013


Author: kledzik
Date: Wed Nov  6 15:36:55 2013
New Revision: 194167

URL: http://llvm.org/viewvc/llvm-project?rev=194167&view=rev
Log:
[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.  


Added:
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
    lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
    lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp
Modified:
    lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
    lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt
    lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
    lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp
    lld/trunk/test/darwin/hello-world.objtxt
    lld/trunk/unittests/MachOTests/CMakeLists.txt

Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Wed Nov  6 15:36:55 2013
@@ -15,6 +15,9 @@
 #include "lld/ReaderWriter/Writer.h"
 
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MachO.h"
+
+using llvm::MachO::HeaderFileType;
 
 namespace lld {
 
@@ -38,12 +41,14 @@ public:
   bool addEntryPointLoadCommand() const;
   bool addUnixThreadLoadCommand() const;
   bool outputTypeHasEntry() const;
+  bool is64Bit() const;
 
   virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
+  virtual uint64_t pageSize() const { return _pageSize; }
 
   mach_o::KindHandler &kindHandler() const;
 
-  uint32_t outputFileType() const { return _outputFileType; }
+  HeaderFileType outputFileType() const { return _outputFileType; }
 
   enum Arch {
     arch_unknown,
@@ -62,7 +67,7 @@ public:
   Arch arch() const { return _arch; }
   OS os() const { return _os; }
 
-  void setOutputFileType(uint32_t type) { _outputFileType = type; }
+  void setOutputFileType(HeaderFileType type) { _outputFileType = type; }
   void setArch(Arch arch) { _arch = arch; }
   bool setOS(OS os, StringRef minOSVersion);
   bool minOS(StringRef mac, StringRef iOS) const;
@@ -116,11 +121,15 @@ public:
     _deadStrippableDylib = deadStrippable;
   }
   void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
+  StringRef dyldPath() const { return "/usr/lib/dyld"; }
 
   static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
   static Arch archFromName(StringRef archName);
   static uint32_t cpuTypeFromArch(Arch arch);
   static uint32_t cpuSubtypeFromArch(Arch arch);
+  static bool is64Bit(Arch arch);
+  static bool isHostEndian(Arch arch);
+  static bool isBigEndian(Arch arch);
 
   /// Construct 32-bit value from string "X.Y.Z" where
   /// bits are xxxx.yy.zz.  Largest number is 65535.255.255
@@ -129,13 +138,25 @@ public:
 private:
   virtual Writer &writer() const;
 
-  uint32_t _outputFileType;   // e.g MH_EXECUTE
+  struct ArchInfo {
+    StringRef                 archName;
+    MachOLinkingContext::Arch arch;
+    bool                      littleEndian;
+    uint32_t                  cputype;
+    uint32_t                  cpusubtype;
+  };
+
+  static ArchInfo _s_archInfos[];
+  const uint64_t unspecifiedPageZeroSize = UINT64_MAX;
+
+  HeaderFileType _outputFileType;   // e.g MH_EXECUTE
   bool _outputFileTypeStatic; // Disambiguate static vs dynamic prog
   bool _doNothing;            // for -help and -v which just print info
   Arch _arch;
   OS _os;
   uint32_t _osMinVersion;
   uint64_t _pageZeroSize;
+  uint64_t _pageSize;
   uint32_t _compatibilityVersion;
   uint32_t _currentVersion;
   StringRef _installName;
@@ -144,6 +165,8 @@ private:
   mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;
   mutable std::unique_ptr<Reader> _machoReader;
   mutable std::unique_ptr<Writer> _writer;
+  
+
 };
 
 } // end namespace lld

Modified: lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt Wed Nov  6 15:36:55 2013
@@ -1,5 +1,8 @@
 add_lld_library(lldMachO
   MachOLinkingContext.cpp
+  MachONormalizedFileBinaryReader.cpp
+  MachONormalizedFileBinaryWriter.cpp
+  MachONormalizedFileFromAtoms.cpp
   MachONormalizedFileYAML.cpp
   ReferenceKinds.cpp
   WriterMachO.cpp

Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Wed Nov  6 15:36:55 2013
@@ -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 @@ bool MachOLinkingContext::parsePackedVer
   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 @@ uint32_t MachOLinkingContext::getCPUSubT
   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::minOS(StringRe
 }
 
 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::addEntryPointL
 
 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::addUnixThreadL
 }
 
 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 @@ bool MachOLinkingContext::validateImpl(r
     }
   }
 
-  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 @@ bool MachOLinkingContext::setOS(OS os, S
 }
 
 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()));
 }
 

Added: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp?rev=194167&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp (added)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp Wed Nov  6 15:36:55 2013
@@ -0,0 +1,310 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts from
+/// mach-o on-disk binary format to in-memory normalized mach-o.
+///
+///                 +---------------+
+///                 | binary mach-o |
+///                 +---------------+
+///                        |
+///                        |
+///                        v
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+#include <functional>
+
+using namespace llvm::MachO;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+// Utility to call a lambda expression on each load command.
+static error_code 
+forEachLoadCommand(StringRef lcRange, unsigned lcCount, bool swap, bool is64,
+                   std::function<bool (uint32_t cmd, uint32_t size, 
+                                                      const char* lc)> func) {
+  const char* p = lcRange.begin();
+  for (unsigned i=0; i < lcCount; ++i) {
+    const load_command *lc = reinterpret_cast<const load_command*>(p);
+    load_command lcCopy;
+    const load_command *slc = lc;
+    if (swap) {
+      memcpy(&lcCopy, lc, sizeof(load_command));
+      swapStruct(lcCopy);
+      slc = &lcCopy;
+    }
+    if ( (p + slc->cmdsize) > lcRange.end() )
+      return llvm::make_error_code(llvm::errc::executable_format_error);
+  
+    if (func(slc->cmd, slc->cmdsize, p))
+      return error_code::success();
+  
+    p += slc->cmdsize;
+  } 
+  
+  return error_code::success();
+}
+
+
+static error_code 
+appendRelocations(Relocations &relocs, StringRef buffer, bool swap, 
+                             bool bigEndian, uint32_t reloff, uint32_t nreloc) {
+  if ((reloff + nreloc*8) > buffer.size())
+    return llvm::make_error_code(llvm::errc::executable_format_error);
+  const any_relocation_info* relocsArray = 
+            reinterpret_cast<const any_relocation_info*>(buffer.begin()+reloff); 
+  
+  for(uint32_t i=0; i < nreloc; ++i) {
+    relocs.push_back(unpackRelocation(relocsArray[i], swap, bigEndian));
+  }
+  return error_code::success();
+}
+
+
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+ErrorOr<std::unique_ptr<NormalizedFile>> 
+readBinary(std::unique_ptr<MemoryBuffer> &mb) {
+  // Make empty NormalizedFile.
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+  // Determine endianness and pointer size for mach-o file.
+  const mach_header *mh = reinterpret_cast<const mach_header*>
+                                                      (mb->getBufferStart());
+  bool is64, swap;
+  switch (mh->magic) {
+  case llvm::MachO::MH_MAGIC:
+    is64 = false;
+    swap = false;
+    break;
+  case llvm::MachO::MH_MAGIC_64:
+    is64 = true;
+    swap = false;
+    break;
+  case llvm::MachO::MH_CIGAM:
+    is64 = false;
+    swap = true;
+    break;
+  case llvm::MachO::MH_CIGAM_64:
+    is64 = true;
+    swap = true;
+    break;
+  default:
+    return llvm::make_error_code(llvm::errc::executable_format_error);
+  }
+
+  // Endian swap header, if needed.
+  mach_header headerCopy;
+  const mach_header *smh = mh;
+  if (swap) {
+    memcpy(&headerCopy, mh, sizeof(mach_header));
+    swapStruct(headerCopy);
+    smh = &headerCopy;
+  }
+
+  // Validate head and load commands fit in buffer.
+  const uint32_t lcCount = smh->ncmds;
+  const char* lcStart = mb->getBufferStart() + (is64 ? sizeof(mach_header_64) 
+                                                     : sizeof(mach_header));
+  StringRef lcRange(lcStart, smh->sizeofcmds);
+  if (lcRange.end() > mb->getBufferEnd())
+    return llvm::make_error_code(llvm::errc::executable_format_error);
+
+  // Normalize architecture
+  f->arch = MachOLinkingContext::archFromCpuType(smh->cputype, smh->cpusubtype);
+  bool isBigEndianArch = MachOLinkingContext::isBigEndian(f->arch);
+  // Copy file type and flags
+  f->fileType = HeaderFileType(smh->filetype);
+  f->flags = smh->flags;
+
+
+  // Walk load commands looking for segments/sections and the symbol table.
+  error_code ec = forEachLoadCommand(lcRange, lcCount, swap, is64, 
+                    [&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
+    if (is64) {
+      if (cmd == LC_SEGMENT_64) {
+        const segment_command_64 *seg = 
+                              reinterpret_cast<const segment_command_64*>(lc);
+        const unsigned sectionCount = (swap ? SwapByteOrder(seg->nsects)
+                                            : seg->nsects);
+        const section_64 *sects = reinterpret_cast<const section_64*>
+                                  (lc + sizeof(segment_command_64));
+        const unsigned lcSize = sizeof(segment_command_64) 
+                                              + sectionCount*sizeof(section_64);
+        // Verify sections don't extend beyond end of segment load command.
+        if (lcSize > size) 
+          return llvm::make_error_code(llvm::errc::executable_format_error);
+        for (unsigned i=0; i < sectionCount; ++i) {
+          const section_64 *sect = &sects[i];
+          Section section;
+          section.segmentName = getString16(sect->segname);
+          section.sectionName = getString16(sect->sectname);
+          section.type        = (SectionType)(read32(swap, sect->flags) 
+                                                                & SECTION_TYPE);
+          section.attributes  = read32(swap, sect->flags) & SECTION_ATTRIBUTES;
+          section.alignment   = read32(swap, sect->align);
+          section.address     = read64(swap, sect->addr);
+          const char *content = mb->getBufferStart() 
+                                           + read32(swap, sect->offset);
+          size_t contentSize = read64(swap, sect->size);
+          // Note: this assign() is copying the content bytes.  Ideally,
+          // we can use a custom allocator for vector to avoid the copy.
+          section.content.assign(content, content+contentSize);
+          appendRelocations(section.relocations, mb->getBuffer(), 
+                            swap, isBigEndianArch, read32(swap, sect->reloff), 
+                                                   read32(swap, sect->nreloc));
+          f->sections.push_back(section);
+        }
+      }
+    } else {
+      if (cmd == LC_SEGMENT) {
+        const segment_command *seg = 
+                              reinterpret_cast<const segment_command*>(lc);
+        const unsigned sectionCount = (swap ? SwapByteOrder(seg->nsects)
+                                            : seg->nsects);
+        const section *sects = reinterpret_cast<const section*>
+                                  (lc + sizeof(segment_command));
+        const unsigned lcSize = sizeof(segment_command) 
+                                              + sectionCount*sizeof(section);
+        // Verify sections don't extend beyond end of segment load command.
+        if (lcSize > size) 
+          return llvm::make_error_code(llvm::errc::executable_format_error);
+        for (unsigned i=0; i < sectionCount; ++i) {
+          const section *sect = &sects[i];
+          Section section;
+          section.segmentName = getString16(sect->segname);
+          section.sectionName = getString16(sect->sectname);
+          section.type        = (SectionType)(read32(swap, sect->flags) 
+                                                                & SECTION_TYPE);
+          section.attributes  = read32(swap, sect->flags) & SECTION_ATTRIBUTES;
+          section.alignment   = read32(swap, sect->align);
+          section.address     = read32(swap, sect->addr);
+          const char *content = mb->getBufferStart() 
+                                           + read32(swap, sect->offset);
+          size_t contentSize = read32(swap, sect->size);
+          // Note: this assign() is copying the content bytes.  Ideally,
+          // we can use a custom allocator for vector to avoid the copy.
+          section.content.assign(content, content+contentSize);
+          appendRelocations(section.relocations, mb->getBuffer(), 
+                            swap, isBigEndianArch, read32(swap, sect->reloff), 
+                                                   read32(swap, sect->nreloc));
+          f->sections.push_back(section);
+        }
+      }
+    }
+    if (cmd == LC_SYMTAB) {
+      const symtab_command *st = reinterpret_cast<const symtab_command*>(lc);
+      const char* strings = mb->getBufferStart() + read32(swap, st->stroff);
+      const uint32_t strSize = read32(swap, st->strsize);
+      // Validate string pool and symbol table all in buffer.
+      if ( read32(swap, st->stroff)+read32(swap, st->strsize) 
+                                                        > mb->getBufferSize() )
+        return llvm::make_error_code(llvm::errc::executable_format_error);
+      if (is64) {
+        const uint32_t symOffset = read32(swap, st->symoff);
+        const uint32_t symCount = read32(swap, st->nsyms);
+        if ( symOffset+(symCount*sizeof(nlist_64)) > mb->getBufferSize())
+          return llvm::make_error_code(llvm::errc::executable_format_error);
+        const nlist_64* symbols = reinterpret_cast<const nlist_64*> 
+                                            (mb->getBufferStart() + symOffset);
+        // Convert each nlist_64 to a lld::mach_o::normalized::Symbol.
+        for(uint32_t i=0; i < symCount; ++i) {
+          const nlist_64 *sin = &symbols[i];
+          nlist_64 tempSym;
+          if (swap) {
+            tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
+          }
+          Symbol sout;
+          if (sin->n_strx > strSize) 
+            return llvm::make_error_code(llvm::errc::executable_format_error);
+          sout.name  = &strings[sin->n_strx];
+          sout.type  = (NListType)(sin->n_type & N_TYPE);
+          sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+          sout.sect  = sin->n_sect;
+          sout.desc  = sin->n_desc;
+          sout.value = sin->n_value;
+          if (sout.type == N_UNDF)
+            f->undefinedSymbols.push_back(sout);
+          else if (sout.scope == (SymbolScope)N_EXT)
+            f->globalSymbols.push_back(sout);
+          else
+            f->localSymbols.push_back(sout);
+        }
+      } else { 
+        const uint32_t symOffset = read32(swap, st->symoff);
+        const uint32_t symCount = read32(swap, st->nsyms);
+        if ( symOffset+(symCount*sizeof(nlist)) > mb->getBufferSize())
+          return llvm::make_error_code(llvm::errc::executable_format_error);
+        const nlist* symbols = reinterpret_cast<const nlist*> 
+                                            (mb->getBufferStart() + symOffset);
+        // Convert each nlist to a lld::mach_o::normalized::Symbol.
+        for(uint32_t i=0; i < symCount; ++i) {
+          const nlist *sin = &symbols[i];
+          nlist tempSym;
+          if (swap) {
+            tempSym = *sin; swapStruct(tempSym); sin = &tempSym;
+          }
+          Symbol sout;
+          if (sin->n_strx > strSize) 
+            return llvm::make_error_code(llvm::errc::executable_format_error);
+          sout.name  = &strings[sin->n_strx];
+          sout.type  = (NListType)(sin->n_type & N_TYPE);
+          sout.scope = (sin->n_type & (N_PEXT|N_EXT));
+          sout.sect  = sin->n_sect;
+          sout.desc  = sin->n_desc;
+          sout.value = sin->n_value;
+          if (sout.type == N_UNDF)
+            f->undefinedSymbols.push_back(sout);
+          else if (sout.scope == (SymbolScope)N_EXT)
+            f->globalSymbols.push_back(sout);
+          else
+            f->localSymbols.push_back(sout);
+        }
+      }
+    } else if (cmd == LC_DYSYMTAB) {
+      // TODO: indirect symbols 
+    }
+
+    return false;
+  });
+  if (ec) 
+    return ec;
+
+  return std::move(f);
+}
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+

Added: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h?rev=194167&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h (added)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h Wed Nov  6 15:36:55 2013
@@ -0,0 +1,293 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "MachONormalizedFile.h"
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/system_error.h"
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_UILS_H_
+#define LLD_READER_WRITER_MACHO_NORMALIZED_UILS_H_
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+using llvm::sys::SwapByteOrder;
+
+inline void swapStruct(llvm::MachO::mach_header &mh) {
+  mh.magic      = SwapByteOrder(mh.magic);
+  mh.cputype    = SwapByteOrder(mh.cputype);
+  mh.cpusubtype = SwapByteOrder(mh.cpusubtype);
+  mh.filetype   = SwapByteOrder(mh.filetype);
+  mh.ncmds      = SwapByteOrder(mh.ncmds);
+  mh.sizeofcmds = SwapByteOrder(mh.sizeofcmds);
+  mh.flags      = SwapByteOrder(mh.flags);
+}
+
+inline void swapStruct(llvm::MachO::load_command &lc) {
+  lc.cmd      = SwapByteOrder(lc.cmd);
+  lc.cmdsize  = SwapByteOrder(lc.cmdsize);
+}
+
+inline void swapStruct(llvm::MachO::symtab_command &lc) {
+  lc.cmd      = SwapByteOrder(lc.cmd);
+  lc.cmdsize  = SwapByteOrder(lc.cmdsize);
+  lc.symoff   = SwapByteOrder(lc.symoff);
+  lc.nsyms    = SwapByteOrder(lc.nsyms);
+  lc.stroff   = SwapByteOrder(lc.stroff);
+  lc.strsize  = SwapByteOrder(lc.strsize);
+}
+
+inline void swapStruct(llvm::MachO::segment_command_64 &seg) {
+  seg.cmd      = SwapByteOrder(seg.cmd);
+  seg.cmdsize  = SwapByteOrder(seg.cmdsize);
+  seg.vmaddr   = SwapByteOrder(seg.vmaddr);
+  seg.vmsize   = SwapByteOrder(seg.vmsize);
+  seg.fileoff  = SwapByteOrder(seg.fileoff);
+  seg.filesize = SwapByteOrder(seg.filesize);
+  seg.maxprot  = SwapByteOrder(seg.maxprot);
+  seg.initprot = SwapByteOrder(seg.initprot);
+  seg.nsects   = SwapByteOrder(seg.nsects);
+  seg.flags    = SwapByteOrder(seg.flags);
+}
+
+inline void swapStruct(llvm::MachO::segment_command &seg) {
+  seg.cmd      = SwapByteOrder(seg.cmd);
+  seg.cmdsize  = SwapByteOrder(seg.cmdsize);
+  seg.vmaddr   = SwapByteOrder(seg.vmaddr);
+  seg.vmsize   = SwapByteOrder(seg.vmsize);
+  seg.fileoff  = SwapByteOrder(seg.fileoff);
+  seg.filesize = SwapByteOrder(seg.filesize);
+  seg.maxprot  = SwapByteOrder(seg.maxprot);
+  seg.initprot = SwapByteOrder(seg.initprot);
+  seg.nsects   = SwapByteOrder(seg.nsects);
+  seg.flags    = SwapByteOrder(seg.flags);
+}
+
+inline void swapStruct(llvm::MachO::section_64 &sect) {
+  sect.addr      = SwapByteOrder(sect.addr);
+  sect.size      = SwapByteOrder(sect.size);
+  sect.offset    = SwapByteOrder(sect.offset);
+  sect.align     = SwapByteOrder(sect.align);
+  sect.reloff    = SwapByteOrder(sect.reloff);
+  sect.nreloc    = SwapByteOrder(sect.nreloc);
+  sect.flags     = SwapByteOrder(sect.flags);
+  sect.reserved1 = SwapByteOrder(sect.reserved1);
+  sect.reserved2 = SwapByteOrder(sect.reserved2);
+}
+
+inline void swapStruct(llvm::MachO::section &sect) {
+  sect.addr      = SwapByteOrder(sect.addr);
+  sect.size      = SwapByteOrder(sect.size);
+  sect.offset    = SwapByteOrder(sect.offset);
+  sect.align     = SwapByteOrder(sect.align);
+  sect.reloff    = SwapByteOrder(sect.reloff);
+  sect.nreloc    = SwapByteOrder(sect.nreloc);
+  sect.flags     = SwapByteOrder(sect.flags);
+  sect.reserved1 = SwapByteOrder(sect.reserved1);
+  sect.reserved2 = SwapByteOrder(sect.reserved2);
+}
+
+inline void swapStruct(llvm::MachO::dyld_info_command &info) {
+  info.cmd            = SwapByteOrder(info.cmd);
+  info.cmdsize        = SwapByteOrder(info.cmdsize);
+  info.rebase_off     = SwapByteOrder(info.rebase_off);
+  info.rebase_size    = SwapByteOrder(info.rebase_size);
+  info.bind_off       = SwapByteOrder(info.bind_off);
+  info.bind_size      = SwapByteOrder(info.bind_size);
+  info.weak_bind_off  = SwapByteOrder(info.weak_bind_off);
+  info.weak_bind_size = SwapByteOrder(info.weak_bind_size);
+  info.lazy_bind_off  = SwapByteOrder(info.lazy_bind_off);
+  info.lazy_bind_size = SwapByteOrder(info.lazy_bind_size);
+  info.export_off     = SwapByteOrder(info.export_off);
+  info.export_size    = SwapByteOrder(info.export_size);
+}
+
+inline void swapStruct(llvm::MachO::dylib_command &d) {
+  d.cmd                         = SwapByteOrder(d.cmd);
+  d.cmdsize                     = SwapByteOrder(d.cmdsize);
+  d.dylib.name                  = SwapByteOrder(d.dylib.name);
+  d.dylib.timestamp             = SwapByteOrder(d.dylib.timestamp);
+  d.dylib.current_version       = SwapByteOrder(d.dylib.current_version);
+  d.dylib.compatibility_version = SwapByteOrder(d.dylib.compatibility_version);
+}
+
+inline void swapStruct(llvm::MachO::dylinker_command &d) {
+  d.cmd       = SwapByteOrder(d.cmd);
+  d.cmdsize   = SwapByteOrder(d.cmdsize);
+  d.name      = SwapByteOrder(d.name);
+}
+
+inline void swapStruct(llvm::MachO::entry_point_command &e) {
+  e.cmd        = SwapByteOrder(e.cmd);
+  e.cmdsize    = SwapByteOrder(e.cmdsize);
+  e.entryoff   = SwapByteOrder(e.entryoff);
+  e.stacksize  = SwapByteOrder(e.stacksize);
+}
+
+inline void swapStruct(llvm::MachO::dysymtab_command &dst) {
+  dst.cmd             = SwapByteOrder(dst.cmd);
+  dst.cmdsize         = SwapByteOrder(dst.cmdsize);
+  dst.ilocalsym       = SwapByteOrder(dst.ilocalsym);
+  dst.nlocalsym       = SwapByteOrder(dst.nlocalsym);
+  dst.iextdefsym      = SwapByteOrder(dst.iextdefsym);
+  dst.nextdefsym      = SwapByteOrder(dst.nextdefsym);
+  dst.iundefsym       = SwapByteOrder(dst.iundefsym);
+  dst.nundefsym       = SwapByteOrder(dst.nundefsym);
+  dst.tocoff          = SwapByteOrder(dst.tocoff);
+  dst.ntoc            = SwapByteOrder(dst.ntoc);
+  dst.modtaboff       = SwapByteOrder(dst.modtaboff);
+  dst.nmodtab         = SwapByteOrder(dst.nmodtab);
+  dst.extrefsymoff    = SwapByteOrder(dst.extrefsymoff);
+  dst.nextrefsyms     = SwapByteOrder(dst.nextrefsyms);
+  dst.indirectsymoff  = SwapByteOrder(dst.indirectsymoff);
+  dst.nindirectsyms   = SwapByteOrder(dst.nindirectsyms);
+  dst.extreloff       = SwapByteOrder(dst.extreloff);
+  dst.nextrel         = SwapByteOrder(dst.nextrel);
+  dst.locreloff       = SwapByteOrder(dst.locreloff);
+  dst.nlocrel         = SwapByteOrder(dst.nlocrel);
+}
+
+
+inline void swapStruct(llvm::MachO::any_relocation_info &reloc) {
+  reloc.r_word0 = SwapByteOrder(reloc.r_word0);
+  reloc.r_word1 = SwapByteOrder(reloc.r_word1);
+}
+
+inline void swapStruct(llvm::MachO::nlist &sym) {
+  sym.n_strx = SwapByteOrder(sym.n_strx);
+  sym.n_desc = SwapByteOrder(sym.n_desc);
+  sym.n_value = SwapByteOrder(sym.n_value);
+}
+
+inline void swapStruct(llvm::MachO::nlist_64 &sym) {
+  sym.n_strx = SwapByteOrder(sym.n_strx);
+  sym.n_desc = SwapByteOrder(sym.n_desc);
+  sym.n_value = SwapByteOrder(sym.n_value);
+}
+
+
+
+
+inline uint32_t read32(bool swap, uint32_t value) {
+    return (swap ? SwapByteOrder(value) : value);
+}
+
+inline uint64_t read64(bool swap, uint64_t value) {
+    return (swap ? SwapByteOrder(value) : value);
+}
+
+
+
+inline uint32_t 
+bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit, 
+                                                          uint8_t bitCount) {
+  const uint32_t mask = ((1<<bitCount)-1); 
+  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+  return (value >> shift) & mask;
+}
+
+inline void 
+bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits, 
+                            uint8_t firstBit, uint8_t bitCount) {
+  const uint32_t mask = ((1<<bitCount)-1); 
+  assert((newBits & mask) == newBits);
+  const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount) : firstBit;
+  bits &= ~(mask << shift);
+  bits |= (newBits << shift);
+}
+
+inline Relocation 
+unpackRelocation(const llvm::MachO::any_relocation_info &r, bool swap, 
+                                                            bool isBigEndian) {
+  uint32_t r0 = read32(swap, r.r_word0);
+  uint32_t r1 = read32(swap, r.r_word1);
+ 
+  Relocation result;
+  if (r0 & llvm::MachO::R_SCATTERED) {
+    // scattered relocation record always laid out like big endian bit field
+    result.offset     = bitFieldExtract(r0, true, 8, 24);
+    result.scattered  = true;
+    result.type       = (RelocationInfoType)
+                        bitFieldExtract(r0, true, 4, 4);
+    result.length     = bitFieldExtract(r0, true, 2, 2);
+    result.pcRel      = bitFieldExtract(r0, true, 1, 1);
+    result.isExtern   = false;
+    result.value      = r1;
+    result.symbol     = 0;
+  } else {
+    result.offset     = r0;
+    result.scattered  = false;
+    result.type       = (RelocationInfoType)
+                        bitFieldExtract(r1, isBigEndian, 28, 4);
+    result.length     = bitFieldExtract(r1, isBigEndian, 25, 2);
+    result.pcRel      = bitFieldExtract(r1, isBigEndian, 24, 1);
+    result.isExtern   = bitFieldExtract(r1, isBigEndian, 27, 1);
+    result.value      = 0;
+    result.symbol     = bitFieldExtract(r1, isBigEndian, 0, 24);
+  }
+  return result;
+} 
+
+
+inline llvm::MachO::any_relocation_info 
+packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
+  uint32_t r0 = 0;
+  uint32_t r1 = 0;
+  
+  if (r.scattered) {
+    r1 = r.value;
+    bitFieldSet(r0, true, r.offset,    8, 24);
+    bitFieldSet(r0, true, r.type,      4, 4);
+    bitFieldSet(r0, true, r.length,    2, 2);
+    bitFieldSet(r0, true, r.pcRel,     1, 1);
+    bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED
+  } else {
+    r0 = r.offset;
+    bitFieldSet(r1, isBigEndian, r.type,     28, 4);
+    bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1);
+    bitFieldSet(r1, isBigEndian, r.length,   25, 2);
+    bitFieldSet(r1, isBigEndian, r.pcRel,    24, 1);
+    bitFieldSet(r1, isBigEndian, r.symbol,   0,  24);
+  }
+  
+  llvm::MachO::any_relocation_info result;
+  result.r_word0 = swap ? SwapByteOrder(r0) : r0;
+  result.r_word1 = swap ? SwapByteOrder(r1) : r1;
+  return result;
+} 
+
+inline StringRef getString16(const char s[16]) {
+  StringRef x = s;
+  if ( x.size() > 16 )
+    return x.substr(0, 16);
+  else
+    return x;
+}
+
+inline void setString16(StringRef str, char s[16]) {
+  memset(s, 0, 16);
+  memcpy(s, str.begin(), (str.size() > 16) ? 16: str.size());
+}
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZED_UILS_H_

Added: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=194167&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (added)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Wed Nov  6 15:36:55 2013
@@ -0,0 +1,1079 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp ---------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file For mach-o object files, this implementation converts normalized 
+/// mach-o in memory to mach-o binary on disk.
+///
+///                 +---------------+  
+///                 | binary mach-o |  
+///                 +---------------+  
+///                        ^
+///                        |
+///                        |
+///                  +------------+  
+///                  | normalized | 
+///                  +------------+ 
+
+#include "MachONormalizedFile.h"
+#include "MachONormalizedFileBinaryUtils.h"
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+#include <functional>
+#include <map>
+
+using namespace llvm::MachO;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Utility class for writing a mach-o binary file given an in-memory
+/// normalized file.  
+class MachOFileLayout {
+public:
+              /// All layout computation is done in the constructor.
+              MachOFileLayout(const NormalizedFile &file);
+              
+  /// Returns the final file size as computed in the constructor.
+  size_t      size() const;
+
+  /// Writes the normalized file as a binary mach-o file to the specified 
+  /// path.  This does not have a stream interface because the generated
+  /// file may need the 'x' bit set.
+  error_code  writeBinary(StringRef path);
+  
+private:
+  uint32_t    loadCommandsSize(uint32_t &count);
+  void        buildFileOffsets();
+  void        writeMachHeader();
+  error_code  writeLoadCommands();
+  void        writeSectionContent();
+  void        writeRelocations();
+  void        writeSymbolTable();
+  void        writeRebaseInfo();
+  void        writeBindingInfo();
+  void        writeLazyBindingInfo();
+  void        writeLinkEditContent();
+  void        buildLinkEditInfo();
+  void        buildRebaseInfo();
+  void        buildBindInfo();
+  void        buildLazyBindInfo();
+  void        computeSymbolTableSizes();
+  void        buildSectionRelocations();
+  void        appendSymbols(const std::vector<Symbol> &symbols,
+                                      uint32_t &symOffset, uint32_t &strOffset);
+  uint32_t    indirectSymbolIndex(const Section &sect, uint32_t &index);
+  uint32_t    indirectSymbolElementSize(const Section &sect);
+
+  error_code  writeSingleSegment32LoadCommand(uint8_t *&lc);
+  error_code  writeSingleSegment64LoadCommand(uint8_t *&lc);
+  error_code  writeSegment32LoadCommands(uint8_t *&lc);
+  error_code  writeSegment64LoadCommands(uint8_t *&lc);
+  
+  uint32_t pointerAlign(uint32_t value);
+  static StringRef dyldPath();
+  
+  class ByteBuffer {
+  public:
+    ByteBuffer();
+    void append_byte(uint8_t);
+    void append_uleb128(uint64_t);
+    void append_sleb128(int64_t);
+    void append_string(StringRef);
+    void align(unsigned);
+    size_t size();
+    const uint8_t *bytes();
+  private:
+    std::vector<uint8_t> _bytes;
+  };
+  
+  struct SegExtraInfo {
+    uint32_t                    fileOffset;
+    std::vector<const Section*> sections;
+  };
+  typedef std::map<const Segment*, SegExtraInfo> SegMap;
+  struct SectionExtraInfo {
+    uint32_t                    fileOffset;
+  };
+  typedef std::map<const Section*, SectionExtraInfo> SectionMap;
+  
+  const NormalizedFile &_file;
+  error_code            _ec;
+  uint8_t              *_buffer;
+  const bool            _is64;
+  const bool            _swap;
+  const bool            _bigEndianArch;
+  uint64_t              _seg1addr;
+  uint32_t              _startOfLoadCommands;
+  uint32_t              _countOfLoadCommands;
+  uint32_t              _endOfLoadCommands;
+  uint32_t              _startOfRelocations;
+  uint32_t              _startOfSymbols;
+  uint32_t              _startOfIndirectSymbols;
+  uint32_t              _startOfSymbolStrings;
+  uint32_t              _endOfSymbolStrings;
+  uint32_t              _symbolTableLocalsStartIndex;
+  uint32_t              _symbolTableGlobalsStartIndex;
+  uint32_t              _symbolTableUndefinesStartIndex;
+  uint32_t              _symbolStringPoolSize;
+  uint32_t              _symbolTableSize;
+  uint32_t              _indirectSymbolTableCount;
+  // Used in object file creation only
+  uint32_t              _startOfSectionsContent;
+  uint32_t              _endOfSectionsContent;
+  // Used in final linked image only
+  uint32_t              _startOfLinkEdit;
+  uint32_t              _startOfRebaseInfo;
+  uint32_t              _endOfRebaseInfo;
+  uint32_t              _startOfBindingInfo;
+  uint32_t              _endOfBindingInfo;
+  uint32_t              _startOfLazyBindingInfo;
+  uint32_t              _endOfLazyBindingInfo;
+  uint32_t              _endOfLinkEdit;
+  uint64_t              _addressOfLinkEdit;
+  SegMap                _segInfo;
+  SectionMap            _sectInfo;
+  ByteBuffer            _rebaseInfo;
+  ByteBuffer            _bindingInfo;
+  ByteBuffer            _lazyBindingInfo;
+  ByteBuffer            _weakBindingInfo;
+  ByteBuffer            _exportInfo;
+};
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
+  MachOFileLayout layout(file);
+  return layout.size();
+}
+
+StringRef MachOFileLayout::dyldPath() {
+  return "/usr/lib/dyld";
+}
+
+uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
+  return llvm::RoundUpToAlignment(value, _is64 ? 8 : 4);
+}  
+
+
+MachOFileLayout::ByteBuffer::ByteBuffer() {
+  _bytes.reserve(256);
+}
+
+void MachOFileLayout::ByteBuffer::append_byte(uint8_t b) {
+  _bytes.push_back(b);
+}
+
+
+void MachOFileLayout::ByteBuffer::append_uleb128(uint64_t value) {
+  uint8_t byte;
+  do {
+    byte = value & 0x7F;
+    value &= ~0x7F;
+    if ( value != 0 )
+      byte |= 0x80;
+    _bytes.push_back(byte);
+    value = value >> 7;
+  } while( byte >= 0x80 );
+}
+
+void MachOFileLayout::ByteBuffer::append_sleb128(int64_t value) {
+  bool isNeg = ( value < 0 );
+  uint8_t byte;
+  bool more;
+  do {
+    byte = value & 0x7F;
+    value = value >> 7;
+    if ( isNeg ) 
+      more = ( (value != -1) || ((byte & 0x40) == 0) );
+    else
+      more = ( (value != 0) || ((byte & 0x40) != 0) );
+    if ( more )
+      byte |= 0x80;
+    _bytes.push_back(byte);
+  } 
+  while( more );
+}
+
+void MachOFileLayout::ByteBuffer::append_string(StringRef str) {
+  _bytes.insert(_bytes.end(), str.begin(), str.end());
+  _bytes.push_back('\0');
+}
+
+void MachOFileLayout::ByteBuffer::align(unsigned alignment) {
+  while ( (_bytes.size() % alignment) != 0 )
+    _bytes.push_back(0);
+}
+
+const uint8_t *MachOFileLayout::ByteBuffer::bytes() {
+  return &_bytes[0];
+}
+
+size_t MachOFileLayout::ByteBuffer::size() {
+  return _bytes.size();
+}
+
+
+ 
+
+MachOFileLayout::MachOFileLayout(const NormalizedFile &file) 
+    : _file(file),
+      _is64(MachOLinkingContext::is64Bit(file.arch)),
+      _swap(!MachOLinkingContext::isHostEndian(file.arch)),
+      _bigEndianArch(MachOLinkingContext::isBigEndian(file.arch)),
+      _seg1addr(INT64_MAX) {
+  _startOfLoadCommands = _is64 ? sizeof(mach_header_64) : sizeof(mach_header);
+  const size_t segCommandBaseSize = 
+          (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+  const size_t sectsSize = (_is64 ? sizeof(section_64) : sizeof(section));
+  if (file.fileType == llvm::MachO::MH_OBJECT) {
+    // object files have just one segment load command containing all sections
+    _endOfLoadCommands = _startOfLoadCommands
+                               + segCommandBaseSize
+                               + file.sections.size() * sectsSize
+                               + sizeof(symtab_command);
+    _countOfLoadCommands = 2;
+    
+    // Accumulate size of each section.
+    _startOfSectionsContent = _endOfLoadCommands;
+    _endOfSectionsContent = _startOfSectionsContent;
+    unsigned relocCount = 0;
+    for (const Section &sect : file.sections) {
+      _sectInfo[&sect].fileOffset = _endOfSectionsContent;
+      _endOfSectionsContent += sect.content.size();
+      relocCount += sect.relocations.size();
+    }
+    
+    computeSymbolTableSizes();
+    
+    // Align start of relocations.
+    _startOfRelocations = pointerAlign(_endOfSectionsContent);    
+    _startOfSymbols = _startOfRelocations + relocCount * 8;
+    // Add Indirect symbol table.
+    _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+    // Align start of symbol table and symbol strings.
+    _startOfSymbolStrings = _startOfIndirectSymbols 
+                  + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+    _endOfSymbolStrings = _startOfSymbolStrings 
+                          + pointerAlign(_symbolStringPoolSize);
+    _endOfLinkEdit = _endOfSymbolStrings;
+    DEBUG_WITH_TYPE("MachOFileLayout", 
+                  llvm::dbgs() << "MachOFileLayout()\n"
+      << "  startOfLoadCommands=" << _startOfLoadCommands << "\n"
+      << "  countOfLoadCommands=" << _countOfLoadCommands << "\n"
+      << "  endOfLoadCommands=" << _endOfLoadCommands << "\n"
+      << "  startOfRelocations=" << _startOfRelocations << "\n"
+      << "  startOfSymbols=" << _startOfSymbols << "\n"
+      << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+      << "  endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+      << "  startOfSectionsContent=" << _startOfSectionsContent << "\n"
+      << "  endOfSectionsContent=" << _endOfSectionsContent << "\n");
+  } else {
+    // Final linked images have one load command per segment.
+    _endOfLoadCommands = _startOfLoadCommands 
+                          + loadCommandsSize(_countOfLoadCommands);
+
+    // Assign section file offsets.
+    buildFileOffsets();
+    buildLinkEditInfo();
+    
+    // LINKEDIT of final linked images has in order:
+    // rebase info, binding info, lazy binding info, weak binding info,
+    // indirect symbol table, symbol table, symbol table strings.
+    _startOfRebaseInfo = _startOfLinkEdit;
+    _endOfRebaseInfo = _startOfRebaseInfo + _rebaseInfo.size();
+    _startOfBindingInfo = _endOfRebaseInfo;
+    _endOfBindingInfo = _startOfBindingInfo + _bindingInfo.size();
+    _startOfLazyBindingInfo = _endOfBindingInfo;
+    _endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
+
+    _startOfSymbols = _endOfLazyBindingInfo;
+    _startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
+    _startOfSymbolStrings = _startOfIndirectSymbols 
+                  + pointerAlign(_indirectSymbolTableCount * sizeof(uint32_t));
+    _endOfSymbolStrings = _startOfSymbolStrings 
+                          + pointerAlign(_symbolStringPoolSize);
+    _endOfLinkEdit = _endOfSymbolStrings;
+    DEBUG_WITH_TYPE("MachOFileLayout", 
+                  llvm::dbgs() << "MachOFileLayout()\n"
+      << "  startOfLoadCommands=" << _startOfLoadCommands << "\n"
+      << "  countOfLoadCommands=" << _countOfLoadCommands << "\n"
+      << "  endOfLoadCommands=" << _endOfLoadCommands << "\n"
+      << "  startOfLinkEdit=" << _startOfLinkEdit << "\n"
+      << "  startOfRebaseInfo=" << _startOfRebaseInfo << "\n"
+      << "  endOfRebaseInfo=" << _endOfRebaseInfo << "\n"
+      << "  startOfBindingInfo=" << _startOfBindingInfo << "\n"
+      << "  endOfBindingInfo=" << _endOfBindingInfo << "\n"
+      << "  startOfLazyBindingInfo=" << _startOfLazyBindingInfo << "\n"
+      << "  endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
+      << "  startOfSymbols=" << _startOfSymbols << "\n"
+      << "  startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
+      << "  endOfSymbolStrings=" << _endOfSymbolStrings << "\n"
+      << "  addressOfLinkEdit=" << _addressOfLinkEdit << "\n");
+  }
+}
+
+uint32_t MachOFileLayout::loadCommandsSize(uint32_t &count) {
+  uint32_t size = 0;
+  count = 0;
+  
+  const size_t segCommandSize = 
+          (_is64 ? sizeof(segment_command_64) : sizeof(segment_command));
+  const size_t sectionSize = (_is64 ? sizeof(section_64) : sizeof(section));
+
+  // Add LC_SEGMENT for each segment.
+  size += _file.segments.size() * segCommandSize;
+  count += _file.segments.size();
+  // Add section record for each section.
+  size += _file.sections.size() * sectionSize;
+  // Add one LC_SEGMENT for implicit  __LINKEDIT segment
+  size += segCommandSize;
+  ++count;
+  
+  // Add LC_DYLD_INFO
+  size += sizeof(dyld_info_command);
+  ++count;
+  
+  // Add LC_SYMTAB
+  size += sizeof(symtab_command);
+  ++count;
+  
+  // Add LC_DYSYMTAB
+  if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+    size += sizeof(dysymtab_command);
+    ++count;
+  }
+    
+  // If main executable add LC_LOAD_DYLINKER and LC_MAIN
+  if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+    size += pointerAlign(sizeof(dylinker_command) + dyldPath().size()+1);
+    ++count;
+    size += sizeof(entry_point_command);
+    ++count;
+  }
+  
+  // Add LC_LOAD_DYLIB for each dependent dylib.
+  for (const DependentDylib &dep : _file.dependentDylibs) {
+    size += sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+    ++count;
+  }
+  
+  return size;
+}
+
+static bool overlaps(const Segment &s1, const Segment &s2) {
+  if (s2.address >= s1.address+s1.size)
+    return false;
+  if (s1.address >= s2.address+s2.size)
+    return false;
+  return true;
+}
+
+static bool overlaps(const Section &s1, const Section &s2) {
+  if (s2.address >= s1.address+s1.content.size())
+    return false;
+  if (s1.address >= s2.address+s2.content.size())
+    return false;
+  return true;
+}
+
+void MachOFileLayout::buildFileOffsets() {
+  // Verify no segments overlap
+  for (const Segment &sg1 : _file.segments) {
+    for (const Segment &sg2 : _file.segments) {
+      if (&sg1 == &sg2)
+        continue;
+      if (overlaps(sg1,sg2)) {
+        _ec = llvm::make_error_code(llvm::errc::executable_format_error);
+        return;
+      }
+    }
+  }
+  
+  // Verify no sections overlap  
+  for (const Section &s1 : _file.sections) {
+    for (const Section &s2 : _file.sections) {
+      if (&s1 == &s2)
+        continue;
+      if (overlaps(s1,s2)) {
+        _ec = llvm::make_error_code(llvm::errc::executable_format_error);
+        return;
+      }
+    }
+  }
+  
+  // Build side table of extra info about segments and sections.
+  SegExtraInfo t;
+  t.fileOffset = 0;
+  for (const Segment &sg : _file.segments) {
+    _segInfo[&sg] = t;
+  }
+  SectionExtraInfo t2;
+  t2.fileOffset = 0;
+  // Assign sections to segments.
+  for (const Section &s : _file.sections) {
+    _sectInfo[&s] = t2;
+    for (const Segment &sg : _file.segments) {
+      if ((s.address >= sg.address) 
+                        && (s.address+s.content.size() <= sg.address+sg.size)) {
+        if (!sg.name.equals(s.segmentName)) {
+          _ec = llvm::make_error_code(llvm::errc::executable_format_error);
+          return;
+        }
+        _segInfo[&sg].sections.push_back(&s);
+      }
+    }
+  }
+  
+  // Assign file offsets.
+  uint32_t fileOffset = 0;
+  DEBUG_WITH_TYPE("MachOFileLayout", 
+                  llvm::dbgs() << "buildFileOffsets()\n");
+  for (const Segment &sg : _file.segments) {
+    // FIXME: 4096  should be infered from segments in normalized file.
+    _segInfo[&sg].fileOffset = llvm::RoundUpToAlignment(fileOffset, 4096);
+    if ((_seg1addr == INT64_MAX) && sg.access)
+      _seg1addr = sg.address;
+    DEBUG_WITH_TYPE("MachOFileLayout", 
+                  llvm::dbgs() << "  segment=" << sg.name
+                  << ", fileOffset=" << _segInfo[&sg].fileOffset << "\n");
+    for (const Section *s : _segInfo[&sg].sections) {
+      fileOffset = s->address - sg.address + _segInfo[&sg].fileOffset;
+      _sectInfo[s].fileOffset = fileOffset;
+      DEBUG_WITH_TYPE("MachOFileLayout", 
+                  llvm::dbgs() << "    section=" << s->sectionName
+                  << ", fileOffset=" << fileOffset << "\n");
+    }
+    _addressOfLinkEdit = sg.address + sg.size;
+  }
+  _startOfLinkEdit = llvm::RoundUpToAlignment(fileOffset, 4096);
+}
+
+
+size_t MachOFileLayout::size() const {
+  return _endOfSymbolStrings;
+}
+
+void MachOFileLayout::writeMachHeader() {
+  mach_header *mh = reinterpret_cast<mach_header*>(_buffer);
+  mh->magic = _is64 ? llvm::MachO::MH_MAGIC_64 : llvm::MachO::MH_MAGIC;
+  mh->cputype =  MachOLinkingContext::cpuTypeFromArch(_file.arch);
+  mh->cpusubtype = MachOLinkingContext::cpuSubtypeFromArch(_file.arch);
+  mh->filetype = _file.fileType;
+  mh->ncmds = _countOfLoadCommands;
+  mh->sizeofcmds = _endOfLoadCommands - _startOfLoadCommands;
+  mh->flags = _file.flags;
+  if (_swap)
+    swapStruct(*mh);
+}
+
+uint32_t MachOFileLayout::indirectSymbolIndex(const Section &sect, 
+                                                   uint32_t &index) {
+  if (sect.indirectSymbols.empty())
+    return 0;
+  uint32_t result = index;
+  index += sect.indirectSymbols.size();
+  return result;
+}
+
+uint32_t MachOFileLayout::indirectSymbolElementSize(const Section &sect) {
+  if (sect.indirectSymbols.empty())
+    return 0;
+  if (sect.type != S_SYMBOL_STUBS)
+    return 0;
+  return sect.content.size() / sect.indirectSymbols.size();
+}
+
+error_code MachOFileLayout::writeSingleSegment64LoadCommand(uint8_t *&lc) {
+  segment_command_64* seg = reinterpret_cast<segment_command_64*>(lc);
+  seg->cmd = LC_SEGMENT_64;
+  seg->cmdsize = sizeof(segment_command_64) 
+                                  + _file.sections.size() * sizeof(section_64);
+  uint8_t *next = lc + seg->cmdsize;
+  memset(seg->segname, 0, 16);
+  seg->vmaddr = 0;
+  seg->vmsize = _endOfSectionsContent - _endOfLoadCommands;
+  seg->fileoff = _endOfLoadCommands;
+  seg->filesize = seg->vmsize;
+  seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->nsects = _file.sections.size();
+  seg->flags = 0;
+  if (_swap)
+    swapStruct(*seg);
+  section_64 *sout = reinterpret_cast<section_64*>
+                                              (lc+sizeof(segment_command_64));
+  uint32_t relOffset = _startOfRelocations;
+  uint32_t contentOffset = _startOfSectionsContent;
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Section &sin : _file.sections) {
+    setString16(sin.sectionName, sout->sectname);
+    setString16(sin.segmentName, sout->segname);
+    sout->addr = sin.address;
+    sout->size = sin.content.size();
+    sout->offset = contentOffset;
+    sout->align = sin.alignment;
+    sout->reloff = sin.relocations.empty() ? 0 : relOffset;
+    sout->nreloc = sin.relocations.size();
+    sout->flags = sin.type | sin.attributes;
+    sout->reserved1 = indirectSymbolIndex(sin, indirectSymRunningIndex);
+    sout->reserved2 = indirectSymbolElementSize(sin);
+    relOffset += sin.relocations.size() * sizeof(any_relocation_info);
+    contentOffset += sin.content.size();
+    if (_swap)
+      swapStruct(*sout);
+    ++sout;
+  }
+  lc = next;
+  return error_code::success();
+}
+
+error_code MachOFileLayout::writeSingleSegment32LoadCommand(uint8_t *&lc) {
+  segment_command* seg = reinterpret_cast<segment_command*>(lc);
+  seg->cmd = LC_SEGMENT;
+  seg->cmdsize = sizeof(segment_command) 
+                              + _file.sections.size() * sizeof(section);
+  uint8_t *next = lc + seg->cmdsize;
+  memset(seg->segname, 0, 16);
+  seg->vmaddr = 0;
+  seg->vmsize = _endOfSectionsContent - _endOfLoadCommands;
+  seg->fileoff = _endOfLoadCommands;
+  seg->filesize = seg->vmsize;
+  seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+  seg->nsects = _file.sections.size();
+  seg->flags = 0;
+  if (_swap)
+    swapStruct(*seg);
+  section *sout = reinterpret_cast<section*>(lc+sizeof(segment_command));
+  uint32_t relOffset = _startOfRelocations;
+  uint32_t contentOffset = _startOfSectionsContent;
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Section &sin : _file.sections) {
+    setString16(sin.sectionName, sout->sectname);
+    setString16(sin.segmentName, sout->segname);
+    sout->addr = sin.address;
+    sout->size = sin.content.size();
+    sout->offset = contentOffset;
+    sout->align = sin.alignment;
+    sout->reloff = sin.relocations.empty() ? 0 : relOffset;
+    sout->nreloc = sin.relocations.size();
+    sout->flags = sin.type | sin.attributes;
+    sout->reserved1 = indirectSymbolIndex(sin, indirectSymRunningIndex);
+    sout->reserved2 = indirectSymbolElementSize(sin);
+    relOffset += sin.relocations.size() * sizeof(any_relocation_info);
+    contentOffset += sin.content.size();
+    if (_swap)
+      swapStruct(*sout);
+    ++sout;
+  }
+  lc = next;
+  return error_code::success();
+}
+
+
+error_code MachOFileLayout::writeSegment64LoadCommands(uint8_t *&lc) {
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Segment &seg : _file.segments) {
+    // Write segment command with trailing sections.
+    SegExtraInfo &segInfo = _segInfo[&seg];
+    segment_command_64* cmd = reinterpret_cast<segment_command_64*>(lc);
+    cmd->cmd = LC_SEGMENT_64;
+    cmd->cmdsize = sizeof(segment_command_64) 
+                                + segInfo.sections.size() * sizeof(section_64);
+    uint8_t *next = lc + cmd->cmdsize;
+    setString16(seg.name, cmd->segname);
+    cmd->vmaddr   = seg.address;
+    cmd->vmsize   = seg.size;
+    cmd->fileoff  = segInfo.fileOffset;
+    cmd->filesize = seg.access ? (uint64_t)seg.size : 0;
+    cmd->maxprot  = seg.access;
+    cmd->initprot = seg.access;
+    cmd->nsects   = segInfo.sections.size();
+    cmd->flags    = 0;
+    if (_swap)
+      swapStruct(*cmd);
+    section_64 *sect = reinterpret_cast<section_64*>
+                                                (lc+sizeof(segment_command_64));
+    for (const Section *section : segInfo.sections) {
+      setString16(section->sectionName, sect->sectname);
+      setString16(section->segmentName, sect->segname);
+      sect->addr      = section->address;
+      sect->size      = section->content.size();
+      sect->offset    = section->address - seg.address + segInfo.fileOffset;
+      sect->align     = section->alignment;
+      sect->reloff    = 0;
+      sect->nreloc    = 0;
+      sect->flags     = section->type | section->attributes;
+      sect->reserved1 = indirectSymbolIndex(*section, indirectSymRunningIndex);
+      sect->reserved2 = indirectSymbolElementSize(*section);
+      if (_swap)
+        swapStruct(*sect);
+      ++sect;
+    }      
+    lc = reinterpret_cast<uint8_t*>(next);
+  }
+  // Add implicit __LINKEDIT segment
+  segment_command_64* cmd = reinterpret_cast<segment_command_64*>(lc);
+  cmd->cmd = LC_SEGMENT_64;
+  cmd->cmdsize = sizeof(segment_command_64);
+  uint8_t *next = lc + cmd->cmdsize;
+  setString16("__LINKEDIT", cmd->segname);
+  cmd->vmaddr   = _addressOfLinkEdit;
+  cmd->vmsize   = _endOfLinkEdit - _startOfLinkEdit;
+  cmd->fileoff  = _startOfLinkEdit;
+  cmd->filesize = _endOfLinkEdit - _startOfLinkEdit;
+  cmd->maxprot  = VM_PROT_READ;
+  cmd->initprot = VM_PROT_READ;
+  cmd->nsects   = 0;
+  cmd->flags    = 0;
+  if (_swap)
+    swapStruct(*cmd);
+  lc = next;
+  return error_code::success();
+}
+
+// FIXME:  See if this can be combined with writeSegment64LoadCommands
+// by using templates.
+error_code MachOFileLayout::writeSegment32LoadCommands(uint8_t *&lc) {
+  uint32_t indirectSymRunningIndex = 0;
+  for (const Segment &seg : _file.segments) {
+    // Write segment command with trailing sections.
+    SegExtraInfo &segInfo = _segInfo[&seg];
+    segment_command* cmd = reinterpret_cast<segment_command*>(lc);
+    cmd->cmd = LC_SEGMENT;
+    cmd->cmdsize = sizeof(segment_command) 
+                                + segInfo.sections.size() * sizeof(section);
+    uint8_t *next = lc + cmd->cmdsize;
+    setString16(seg.name, cmd->segname);
+    cmd->vmaddr   = seg.address;
+    cmd->vmsize   = seg.size;
+    cmd->fileoff  = segInfo.fileOffset;
+    cmd->filesize = seg.access ? (uint32_t)seg.size : 0;
+    cmd->maxprot  = seg.access;
+    cmd->initprot = seg.access;
+    cmd->nsects   = segInfo.sections.size();
+    cmd->flags    = 0;
+    if (_swap)
+      swapStruct(*cmd);
+    section *sect = reinterpret_cast<section*>(lc+sizeof(segment_command));
+    for (const Section *section : segInfo.sections) {
+      setString16(section->sectionName, sect->sectname);
+      setString16(section->segmentName, sect->segname);
+      sect->addr      = section->address;
+      sect->size      = section->content.size();
+      sect->offset    = section->address - seg.address + segInfo.fileOffset;
+      sect->align     = section->alignment;
+      sect->reloff    = 0;
+      sect->nreloc    = 0;
+      sect->flags     = section->type | section->attributes;
+      sect->reserved1 = indirectSymbolIndex(*section, indirectSymRunningIndex);
+      sect->reserved2 = indirectSymbolElementSize(*section);
+      if (_swap)
+        swapStruct(*sect);
+      ++sect;
+    }      
+    lc = reinterpret_cast<uint8_t*>(next);
+  }
+  return error_code::success();
+}
+
+
+error_code MachOFileLayout::writeLoadCommands() {
+  error_code ec;
+  uint8_t *lc = &_buffer[_startOfLoadCommands];
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    // Object files have one unnamed segment which holds all sections.
+    if (_is64)
+      ec = writeSingleSegment64LoadCommand(lc);
+    else
+      ec = writeSingleSegment32LoadCommand(lc);
+    // Add LC_SYMTAB with symbol table info
+    symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+    st->cmd     = LC_SYMTAB;
+    st->cmdsize = sizeof(symtab_command);
+    st->symoff  = _startOfSymbols;
+    st->nsyms   = _file.localSymbols.size() + _file.globalSymbols.size() 
+                                            + _file.undefinedSymbols.size();
+    st->stroff  = _startOfSymbolStrings;
+    st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+    if (_swap)
+      swapStruct(*st);
+  } else {
+    // Final linked images have sections under segments.
+    if (_is64)
+      ec = writeSegment64LoadCommands(lc);
+    else
+      ec = writeSegment32LoadCommands(lc);
+    
+    // Add LC_DYLD_INFO_ONLY.
+    dyld_info_command* di = reinterpret_cast<dyld_info_command*>(lc);
+    di->cmd            = LC_DYLD_INFO_ONLY;
+    di->cmdsize        = sizeof(dyld_info_command);
+    di->rebase_off     = _rebaseInfo.size() ? _startOfRebaseInfo : 0;
+    di->rebase_size    = _rebaseInfo.size();
+    di->bind_off       = _bindingInfo.size() ? _startOfBindingInfo : 0;
+    di->bind_size      = _bindingInfo.size();
+    di->weak_bind_off  = 0;
+    di->weak_bind_size = 0;
+    di->lazy_bind_off  = _lazyBindingInfo.size() ? _startOfLazyBindingInfo : 0;
+    di->lazy_bind_size = _lazyBindingInfo.size();
+    di->export_off     = 0;
+    di->export_size    = 0;
+    if (_swap)
+      swapStruct(*di);
+    lc += sizeof(dyld_info_command);
+
+    // Add LC_SYMTAB with symbol table info.
+    symtab_command* st = reinterpret_cast<symtab_command*>(lc);
+    st->cmd     = LC_SYMTAB;
+    st->cmdsize = sizeof(symtab_command);
+    st->symoff  = _startOfSymbols;
+    st->nsyms   = _file.localSymbols.size() + _file.globalSymbols.size() 
+                                            + _file.undefinedSymbols.size();
+    st->stroff  = _startOfSymbolStrings;
+    st->strsize = _endOfSymbolStrings - _startOfSymbolStrings;
+    if (_swap)
+      swapStruct(*st);
+    lc += sizeof(symtab_command);
+    
+    // Add LC_DYSYMTAB
+    if (_file.fileType != llvm::MachO::MH_PRELOAD) {
+      dysymtab_command* dst = reinterpret_cast<dysymtab_command*>(lc);
+      dst->cmd            = LC_DYSYMTAB;
+      dst->cmdsize        = sizeof(dysymtab_command);
+      dst->ilocalsym      = _symbolTableLocalsStartIndex;
+      dst->nlocalsym      = _file.localSymbols.size();
+      dst->iextdefsym     = _symbolTableGlobalsStartIndex;
+      dst->nextdefsym     = _file.globalSymbols.size();
+      dst->iundefsym      = _symbolTableUndefinesStartIndex;
+      dst->nundefsym      = _file.undefinedSymbols.size();
+      dst->tocoff         = 0;
+      dst->ntoc           = 0;
+      dst->modtaboff      = 0;
+      dst->nmodtab        = 0;
+      dst->extrefsymoff   = 0;
+      dst->nextrefsyms    = 0;
+      dst->indirectsymoff = _startOfIndirectSymbols; 
+      dst->nindirectsyms  = _indirectSymbolTableCount;
+      dst->extreloff      = 0;
+      dst->nextrel        = 0;
+      dst->locreloff      = 0;
+      dst->nlocrel        = 0;
+      if (_swap)
+        swapStruct(*dst);
+      lc += sizeof(dysymtab_command);
+    }
+ 
+    // If main executable, add LC_LOAD_DYLINKER and LC_MAIN.
+    if (_file.fileType == llvm::MachO::MH_EXECUTE) {
+      // Build LC_LOAD_DYLINKER load command.
+      uint32_t size=pointerAlign(sizeof(dylinker_command)+dyldPath().size()+1);
+      dylinker_command* dl = reinterpret_cast<dylinker_command*>(lc);
+      dl->cmd              = LC_LOAD_DYLINKER;
+      dl->cmdsize          = size;
+      dl->name             = sizeof(dylinker_command); // offset
+      if (_swap)
+        swapStruct(*dl);
+      memcpy(lc+sizeof(dylinker_command), dyldPath().data(), dyldPath().size());
+      lc[sizeof(dylinker_command)+dyldPath().size()] = '\0';
+      lc += size;
+      // Build LC_MAIN load command.
+      entry_point_command* ep = reinterpret_cast<entry_point_command*>(lc);
+      ep->cmd       = LC_MAIN;
+      ep->cmdsize   = sizeof(entry_point_command);
+      ep->entryoff  = _file.entryAddress - _seg1addr;
+      ep->stacksize = 0;
+      if (_swap)
+        swapStruct(*ep);
+      lc += sizeof(entry_point_command);
+    }
+  
+    // Add LC_LOAD_DYLIB commands
+    for (const DependentDylib &dep : _file.dependentDylibs) {
+      dylib_command* dc = reinterpret_cast<dylib_command*>(lc);
+      uint32_t size = sizeof(dylib_command) + pointerAlign(dep.path.size()+1);
+      dc->cmd                         = LC_LOAD_DYLIB;
+      dc->cmdsize                     = size;
+      dc->dylib.name                  = sizeof(dylib_command); // offset
+      dc->dylib.timestamp             = 0; // FIXME
+      dc->dylib.current_version       = 0; // FIXME
+      dc->dylib.compatibility_version = 0; // FIXME
+      if (_swap)
+        swapStruct(*dc);
+      memcpy(lc+sizeof(dylib_command), dep.path.begin(), dep.path.size());
+      lc[sizeof(dylib_command)+dep.path.size()] = '\0';
+      lc += size;
+    }
+    
+  }
+  return ec;
+}
+
+
+void MachOFileLayout::writeSectionContent() {
+  for (const Section &s : _file.sections) {
+    // Copy all section content to output buffer.
+    uint32_t offset = _sectInfo[&s].fileOffset;
+    uint8_t *p = &_buffer[offset];
+    memcpy(p, &s.content[0], s.content.size());
+    p += s.content.size();
+  }
+}
+
+void MachOFileLayout::writeRelocations() {
+  uint32_t relOffset = _startOfRelocations;
+  for (Section sect : _file.sections) {
+    for (Relocation r : sect.relocations) {
+      any_relocation_info* rb = reinterpret_cast<any_relocation_info*>(
+                                                           &_buffer[relOffset]);
+      *rb = packRelocation(r, _swap, _bigEndianArch);
+      relOffset += sizeof(any_relocation_info);
+    }
+  }
+}
+
+
+void MachOFileLayout::appendSymbols(const std::vector<Symbol> &symbols,
+                                   uint32_t &symOffset, uint32_t &strOffset) {
+  for (const Symbol &sym : symbols) {
+    if (_is64) {
+      nlist_64* nb = reinterpret_cast<nlist_64*>(&_buffer[symOffset]);
+      nb->n_strx = strOffset - _startOfSymbolStrings;
+      nb->n_type = sym.type | sym.scope;
+      nb->n_sect = sym.sect;
+      nb->n_desc = sym.desc;
+      nb->n_value = sym.value;
+      if (_swap)
+        swapStruct(*nb);
+      symOffset += sizeof(nlist_64);
+    } else {
+      nlist* nb = reinterpret_cast<nlist*>(&_buffer[symOffset]);
+      nb->n_strx = strOffset - _startOfSymbolStrings;
+      nb->n_type = sym.type | sym.scope;
+      nb->n_sect = sym.sect;
+      nb->n_desc = sym.desc;
+      nb->n_value = sym.value;
+      if (_swap)
+        swapStruct(*nb);
+      symOffset += sizeof(nlist);
+    }
+    memcpy(&_buffer[strOffset], sym.name.begin(), sym.name.size());
+    strOffset += sym.name.size();
+    _buffer[strOffset++] ='\0'; // Strings in table have nul terminator.
+  }
+}
+
+void MachOFileLayout::writeSymbolTable() {
+  // Write symbol table and symbol strings in parallel.
+  uint32_t symOffset = _startOfSymbols;
+  uint32_t strOffset = _startOfSymbolStrings;
+  _buffer[strOffset++] = '\0'; // Reserve n_strx offset of zero to mean no name.
+  appendSymbols(_file.localSymbols, symOffset, strOffset);
+  appendSymbols(_file.globalSymbols, symOffset, strOffset);
+  appendSymbols(_file.undefinedSymbols, symOffset, strOffset);
+  // Write indirect symbol table array.
+  uint32_t *indirects = reinterpret_cast<uint32_t*>
+                                            (&_buffer[_startOfIndirectSymbols]);
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    // Object files have sections in same order as input normalized file.
+    for (const Section &section : _file.sections) {
+      for (uint32_t index : section.indirectSymbols) {
+        if (_swap)
+          *indirects++ = SwapByteOrder(index);
+        else
+          *indirects++ = index;
+      }
+    }
+  } else {
+    // Final linked images must sort sections from normalized file.
+    for (const Segment &seg : _file.segments) {
+      SegExtraInfo &segInfo = _segInfo[&seg];
+      for (const Section *section : segInfo.sections) {
+        for (uint32_t index : section->indirectSymbols) {
+          if (_swap)
+            *indirects++ = SwapByteOrder(index);
+          else
+            *indirects++ = index;
+        }
+      }
+    }
+  }
+}
+
+void MachOFileLayout::writeRebaseInfo() {
+  memcpy(&_buffer[_startOfRebaseInfo], _rebaseInfo.bytes(), _rebaseInfo.size());
+}
+
+void MachOFileLayout::writeBindingInfo() {
+  memcpy(&_buffer[_startOfBindingInfo], 
+                                    _bindingInfo.bytes(), _bindingInfo.size());
+}
+
+void MachOFileLayout::writeLazyBindingInfo() {
+  memcpy(&_buffer[_startOfLazyBindingInfo], 
+                            _lazyBindingInfo.bytes(), _lazyBindingInfo.size());
+}
+
+void MachOFileLayout::buildLinkEditInfo() {
+  buildRebaseInfo();
+  buildBindInfo();
+  buildLazyBindInfo();
+  computeSymbolTableSizes();
+}
+
+void MachOFileLayout::buildSectionRelocations() {
+
+}
+
+void MachOFileLayout::buildRebaseInfo() {
+  // TODO: compress rebasing info.
+  for (const RebaseLocation& entry : _file.rebasingInfo) {
+    _rebaseInfo.append_byte(REBASE_OPCODE_SET_TYPE_IMM | entry.kind);
+    _rebaseInfo.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 
+                            | entry.segIndex);
+    _rebaseInfo.append_uleb128(entry.segOffset);
+    _rebaseInfo.append_uleb128(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1);
+  }
+  _rebaseInfo.append_byte(REBASE_OPCODE_DONE); 
+  _rebaseInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildBindInfo() {
+  // TODO: compress bind info.
+  for (const BindLocation& entry : _file.bindingInfo) {
+    _bindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+    _bindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 
+                            | entry.segIndex);
+    _bindingInfo.append_uleb128(entry.segOffset);
+    _bindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | entry.ordinal);
+    _bindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+    _bindingInfo.append_string(entry.symbolName);
+    if (entry.addend != 0) {
+      _bindingInfo.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+      _bindingInfo.append_sleb128(entry.addend);
+    }
+    _bindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+  }
+  _bindingInfo.append_byte(BIND_OPCODE_DONE); 
+  _bindingInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::buildLazyBindInfo() {
+  for (const BindLocation& entry : _file.lazyBindingInfo) {
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_TYPE_IMM | entry.kind);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 
+                            | entry.segIndex);
+    _lazyBindingInfo.append_uleb128(entry.segOffset);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | entry.ordinal);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
+    _lazyBindingInfo.append_string(entry.symbolName);
+    _lazyBindingInfo.append_byte(BIND_OPCODE_DO_BIND);
+  }
+  _lazyBindingInfo.append_byte(BIND_OPCODE_DONE); 
+  _lazyBindingInfo.align(_is64 ? 8 : 4);
+}
+
+void MachOFileLayout::computeSymbolTableSizes() {
+  // MachO symbol tables have three ranges: locals, globals, and undefines
+  const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
+  _symbolTableSize = nlistSize * (_file.localSymbols.size() 
+                                + _file.globalSymbols.size()
+                                + _file.undefinedSymbols.size());
+  _symbolStringPoolSize = 0;                          
+  for (const Symbol &sym : _file.localSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.globalSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  for (const Symbol &sym : _file.undefinedSymbols) {
+    _symbolStringPoolSize += (sym.name.size()+1);
+  }
+  _symbolTableLocalsStartIndex = 0;
+  _symbolTableGlobalsStartIndex = _file.localSymbols.size();
+  _symbolTableUndefinesStartIndex = _symbolTableGlobalsStartIndex 
+                                    + _file.globalSymbols.size();
+
+  _indirectSymbolTableCount = 0;
+  for (const Section &sect : _file.sections) {
+    _indirectSymbolTableCount += sect.indirectSymbols.size();
+  }
+}
+
+
+void MachOFileLayout::writeLinkEditContent() {
+  if (_file.fileType == llvm::MachO::MH_OBJECT) {
+    writeRelocations();
+    writeSymbolTable();
+  } else {
+    writeRebaseInfo();
+    writeBindingInfo();
+    writeLazyBindingInfo();
+    // TODO: add weak binding info
+    writeSymbolTable();
+  }
+}
+
+
+error_code MachOFileLayout::writeBinary(StringRef path) {
+  // Check for pending error from constructor.
+  if (_ec)
+    return _ec;
+  // Create FileOutputBuffer with calculated size.
+  OwningPtr<llvm::FileOutputBuffer> fob;
+  unsigned flags = 0;
+  if (_file.fileType != llvm::MachO::MH_OBJECT)
+    flags = llvm::FileOutputBuffer::F_executable;
+  error_code ec;
+  ec = llvm::FileOutputBuffer::create(path, size(), fob, flags);
+  if (ec)
+    return ec;
+  
+  // Write content.
+  _buffer = fob->getBufferStart();
+  writeMachHeader();
+  ec = writeLoadCommands();
+  if (ec)
+    return ec;
+  writeSectionContent();
+  writeLinkEditContent();
+  fob->commit();
+
+  return error_code::success();
+}
+
+
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+error_code 
+writeBinary(const NormalizedFile &file, StringRef path) {
+  MachOFileLayout layout(file);
+  return layout.writeBinary(path);
+}
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+

Added: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=194167&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (added)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Wed Nov  6 15:36:55 2013
@@ -0,0 +1,821 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file Converts from in-memory Atoms to in-memory normalized mach-o.
+///
+///                  +------------+
+///                  | normalized |
+///                  +------------+
+///                        ^
+///                        |
+///                        |
+///                    +-------+ 
+///                    | Atoms |
+///                    +-------+ 
+
+#include "MachONormalizedFile.h"
+#include "ReferenceKinds.h"
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/system_error.h"
+
+#include <map>
+
+using llvm::StringRef;
+using llvm::dyn_cast;
+using llvm::isa;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+using namespace lld;
+
+namespace {
+
+struct AtomInfo {
+  const DefinedAtom  *atom;
+  uint64_t            offsetInSection;
+};
+
+struct SectionInfo {
+  SectionInfo(StringRef seg, StringRef sect, SectionType type, uint32_t attr=0);
+  
+  StringRef                 segmentName;
+  StringRef                 sectionName;
+  SectionType               type;
+  uint32_t                  attributes;
+  uint64_t                  address;
+  uint64_t                  size;
+  uint32_t                  alignment;
+  std::vector<AtomInfo>     atomsAndOffsets;
+  uint32_t                  normalizedSectionIndex;
+  uint32_t                  finalSectionIndex;
+};
+
+SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t, uint32_t a) 
+ : segmentName(sg), sectionName(sct), type(t), attributes(a), 
+                 address(0), size(0), alignment(0), 
+                 normalizedSectionIndex(0), finalSectionIndex(0) {
+}
+
+struct SegmentInfo {
+  SegmentInfo(StringRef name);
+  
+  StringRef                  name;
+  uint64_t                   address;
+  uint64_t                   size;
+  uint32_t                   access;
+  std::vector<SectionInfo*>  sections;
+};
+
+SegmentInfo::SegmentInfo(StringRef n) 
+ : name(n), address(0), size(0), access(0) {
+}
+
+
+class Util {
+public:
+  Util(const MachOLinkingContext &ctxt) : _context(ctxt), _entryAtom(nullptr) {}
+
+  void      assignAtomsToSections(const lld::File &atomFile);
+  void      organizeSections();
+  void      assignAddressesToSections();
+  uint32_t  fileFlags();
+  void      copySegmentInfo(NormalizedFile &file);
+  void      copySections(NormalizedFile &file);
+  void      buildAtomToAddressMap();
+  void      addSymbols(const lld::File &atomFile, NormalizedFile &file);
+  void      addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
+  void      addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
+  void      addSectionRelocs(const lld::File &, NormalizedFile &file);
+  void      addDependentDylibs(const lld::File &, NormalizedFile &file);
+  void      copyEntryPointAddress(NormalizedFile &file);
+
+private:
+  typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
+  typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
+  
+  struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; };
+  typedef llvm::StringMap<DylibInfo> DylibPathToInfo;
+  
+  SectionInfo *sectionForAtom(const DefinedAtom*);
+  SectionInfo *makeSection(DefinedAtom::ContentType);
+  void         appendAtom(SectionInfo *sect, const DefinedAtom *atom);
+  SegmentInfo *segmentForName(StringRef segName);
+  void         layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
+  void         layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr);
+  void         copySectionContent(SectionInfo *si, ContentBytes &content);
+  uint8_t      scopeBits(const DefinedAtom* atom);
+  int          dylibOrdinal(const SharedLibraryAtom *sa);
+  void         segIndexForSection(const SectionInfo *sect, 
+                             uint8_t &segmentIndex, uint64_t &segmentStartAddr);
+  const Atom  *targetOfLazyPointer(const DefinedAtom *lpAtom);
+  const Atom  *targetOfStub(const DefinedAtom *stubAtom);
+  bool         belongsInGlobalSymbolsSection(const DefinedAtom* atom);
+  void         appendSection(SectionInfo *si, NormalizedFile &file);
+  void         appendReloc(const DefinedAtom *atom, const Reference *ref, 
+                                                      Relocations &relocations);
+  
+  static uint64_t alignTo(uint64_t value, uint8_t align2);
+  typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
+  struct AtomAndIndex { const Atom *atom; uint32_t index; };
+	struct AtomSorter {	
+		bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
+  };
+	struct SegmentSorter {	
+		bool operator()(const SegmentInfo *left, const SegmentInfo *right);
+    static unsigned weight(const SegmentInfo *);
+  };
+	struct TextSectionSorter {	
+		bool operator()(const SectionInfo *left, const SectionInfo *right);
+    static unsigned weight(const SectionInfo *);
+  };
+
+  const MachOLinkingContext    &_context;
+  llvm::BumpPtrAllocator        _allocator;
+  std::vector<SectionInfo*>     _sectionInfos;
+  std::vector<SegmentInfo*>     _segmentInfos;
+  TypeToSection                 _sectionMap;
+  AtomToAddress                 _atomToAddress;
+  DylibPathToInfo               _dylibInfo;
+  const DefinedAtom            *_entryAtom;
+  AtomToIndex                   _atomToSymbolIndex;
+};
+
+SectionInfo *Util::makeSection(DefinedAtom::ContentType type) {
+  switch ( type ) {
+  case DefinedAtom::typeCode:
+    return new (_allocator) SectionInfo("__TEXT", "__text",
+                             S_REGULAR, S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+  case DefinedAtom::typeCString:
+     return new (_allocator) SectionInfo("__TEXT", "__cstring",
+                             S_CSTRING_LITERALS);
+  case DefinedAtom::typeStub:
+    return new (_allocator) SectionInfo("__TEXT", "__stubs",
+                            S_SYMBOL_STUBS, S_ATTR_PURE_INSTRUCTIONS);
+  case DefinedAtom::typeStubHelper:
+    return new (_allocator) SectionInfo("__TEXT", "__stub_helper",
+                            S_REGULAR, S_ATTR_PURE_INSTRUCTIONS);
+  case DefinedAtom::typeLazyPointer:
+    return new (_allocator) SectionInfo("__DATA", "__la_symbol_ptr",
+                            S_LAZY_SYMBOL_POINTERS);
+  case DefinedAtom::typeGOT:
+     return new (_allocator) SectionInfo("__DATA", "__got",
+                            S_NON_LAZY_SYMBOL_POINTERS);
+  default:
+    llvm_unreachable("TO DO: add support for more sections");
+    break;
+  }
+}
+
+
+
+SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
+  DefinedAtom::ContentType type = atom->contentType();
+  auto pos = _sectionMap.find(type);
+  if ( pos != _sectionMap.end() )
+    return pos->second;
+  SectionInfo *si = makeSection(type);
+  _sectionInfos.push_back(si);
+  _sectionMap[type] = si;
+  return si;
+}
+  
+
+void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
+  // Figure out offset for atom in this section given alignment constraints.
+  uint64_t offset = sect->size;
+  DefinedAtom::Alignment atomAlign = atom->alignment();
+  uint64_t align2 = 1 << atomAlign.powerOf2;
+  uint64_t requiredModulus = atomAlign.modulus;
+  uint64_t currentModulus = (offset % align2);
+  if ( currentModulus != requiredModulus ) {
+    if ( requiredModulus > currentModulus )
+      offset += requiredModulus-currentModulus;
+    else
+      offset += align2+requiredModulus-currentModulus;
+  }
+  // Record max alignment of any atom in this section.
+  if ( atomAlign.powerOf2 > sect->alignment )
+    sect->alignment = atomAlign.powerOf2;
+  // Assign atom to this section with this offset.
+  AtomInfo ai = {atom, offset};
+  sect->atomsAndOffsets.push_back(ai);
+  // Update section size to include this atom.
+  sect->size = offset + atom->size();
+}
+
+void Util::assignAtomsToSections(const lld::File &atomFile) {
+  for (const DefinedAtom *atom : atomFile.defined()) {
+    appendAtom(sectionForAtom(atom), atom);
+  }
+}
+
+SegmentInfo *Util::segmentForName(StringRef segName) {
+  for (SegmentInfo *si : _segmentInfos) {
+    if ( si->name.equals(segName) )
+      return si;
+  }
+  SegmentInfo *info = new (_allocator) SegmentInfo(segName);
+  if (segName.equals("__TEXT"))
+    info->access = VM_PROT_READ | VM_PROT_EXECUTE;
+  else if (segName.equals("__DATA"))
+    info->access = VM_PROT_READ | VM_PROT_WRITE;
+  else if (segName.equals("__PAGEZERO"))
+    info->access = 0;
+  _segmentInfos.push_back(info);
+  return info;
+}
+
+unsigned Util::SegmentSorter::weight(const SegmentInfo *seg) {
+ return llvm::StringSwitch<unsigned>(seg->name)
+    .Case("__PAGEZERO",  1)
+    .Case("__TEXT",      2)
+    .Case("__DATA",      3)
+    .Default(100);
+}
+
+bool Util::SegmentSorter::operator()(const SegmentInfo *left, 
+                                  const SegmentInfo *right) {
+  return (weight(left) < weight(right));
+}
+
+unsigned Util::TextSectionSorter::weight(const SectionInfo *sect) {
+ return llvm::StringSwitch<unsigned>(sect->sectionName)
+    .Case("__text",         1)
+    .Case("__stubs",        2)
+    .Case("__stub_helper",  3)
+    .Case("__const",        4)
+    .Case("__cstring",      5)
+    .Case("__unwind_info",  98)
+    .Case("__eh_frame",     99)
+    .Default(10);
+}
+
+bool Util::TextSectionSorter::operator()(const SectionInfo *left, 
+                                         const SectionInfo *right) {
+  return (weight(left) < weight(right));
+}
+
+
+void Util::organizeSections() {
+  if (_context.outputFileType() == llvm::MachO::MH_OBJECT) {
+    // Leave sections ordered as normalized file specified.
+    uint32_t sectionIndex = 1;
+    for (SectionInfo *si : _sectionInfos) {
+      si->finalSectionIndex = sectionIndex++;
+    }
+  } else {
+    // Main executables, need a zero-page segment
+    if (_context.outputFileType() == llvm::MachO::MH_EXECUTE)
+      segmentForName("__PAGEZERO");
+    // Group sections into segments.
+    for (SectionInfo *si : _sectionInfos) {
+      SegmentInfo *seg = segmentForName(si->segmentName);
+      seg->sections.push_back(si);
+    }
+    // Sort segments.
+    std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
+    
+    // Sort sections within segments.
+    for (SegmentInfo *seg : _segmentInfos) {
+      if (seg->name.equals("__TEXT")) {
+        std::sort(seg->sections.begin(), seg->sections.end(), 
+                                                          TextSectionSorter());
+      }
+    }
+    
+    // Record final section indexes.
+    uint32_t sectionIndex = 1;
+    for (SegmentInfo *seg : _segmentInfos) {
+        for (SectionInfo *sect : seg->sections) {
+          sect->finalSectionIndex = sectionIndex++;
+        }
+    }
+  }
+
+}
+
+uint64_t Util::alignTo(uint64_t value, uint8_t align2) {
+  return llvm::RoundUpToAlignment(value, 1 << align2);
+}
+
+
+void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
+  seg->address = addr;
+  for (SectionInfo *sect : seg->sections) {
+    sect->address = alignTo(addr, sect->alignment);
+    addr += sect->size;
+  }
+  seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
+}
+
+
+// __TEXT segment lays out backwards so padding is at front after load commands.
+void Util::layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr) {
+  seg->address = addr;
+  // Walks sections starting at end to calculate padding for start.
+  int64_t taddr = 0;
+  for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) { 
+    SectionInfo *sect = *it;
+    taddr -= sect->size;
+    taddr = taddr & (0 - (1 << sect->alignment));
+  }
+  int64_t padding = taddr;
+  while (padding < 0)
+    padding += _context.pageSize();
+  // Start assigning section address starting at padded offset.
+  addr += padding;
+  for (SectionInfo *sect : seg->sections) {
+    sect->address = alignTo(addr, sect->alignment);
+    addr = sect->address + sect->size;
+  }
+  seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
+}
+
+
+void Util::assignAddressesToSections() {
+  uint64_t address = 0;  // FIXME
+  if (_context.outputFileType() != llvm::MachO::MH_OBJECT) {
+    for (SegmentInfo *seg : _segmentInfos) {
+      if (seg->name.equals("__PAGEZERO")) {
+        seg->size = _context.pageZeroSize();
+        address += seg->size;
+      }
+      else if (seg->name.equals("__TEXT"))
+        layoutSectionsInTextSegment(seg, address);
+      else
+        layoutSectionsInSegment(seg, address);
+    }
+    DEBUG_WITH_TYPE("WriterMachO-norm", 
+                    llvm::dbgs() << "assignAddressesToSections()\n");
+    for (SegmentInfo *sgi : _segmentInfos) {
+      DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs()
+                      << "   address=" << llvm::format("0x%08llX", sgi->address)
+                      << ", size="  << llvm::format("0x%08llX", sgi->size)
+                      << ", segment-name='" << sgi->name 
+                      << "'\n");
+    for (SectionInfo *si : sgi->sections) {
+        DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs()
+                      << "      addr="  << llvm::format("0x%08llX", si->address)
+                      << ", size="  << llvm::format("0x%08llX", si->size)
+                      << ", section-name='" << si->sectionName 
+                      << "\n");
+      }
+    }
+  } else {
+    for (SectionInfo *sect : _sectionInfos) {
+      sect->address = alignTo(address, sect->alignment);
+      address = sect->address + sect->size;
+    }
+    DEBUG_WITH_TYPE("WriterMachO-norm", 
+                     llvm::dbgs() << "assignAddressesToSections()\n");
+    for (SectionInfo *si : _sectionInfos) {
+      DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs()
+                      << "      section=" << si->sectionName 
+                      << " address= "  << llvm::format("0x%08X", si->address)
+                      << " size= "  << llvm::format("0x%08X", si->size)
+                      << "\n");
+    }
+  }
+
+}
+
+
+void Util::copySegmentInfo(NormalizedFile &file) {
+  for (SegmentInfo *sgi : _segmentInfos) {
+    Segment seg;
+    seg.name    = sgi->name;
+    seg.address = sgi->address;
+    seg.size    = sgi->size;
+    seg.access  = sgi->access;
+    file.segments.push_back(seg);
+  }
+}
+
+void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
+  // Add new empty section to end of file.sections.
+  Section temp;
+  file.sections.push_back(std::move(temp));
+  Section* normSect = &file.sections.back();
+  // Copy fields to normalized section.
+  normSect->segmentName   = si->segmentName;
+  normSect->sectionName   = si->sectionName;
+  normSect->type          = si->type;
+  normSect->attributes    = si->attributes;
+  normSect->address       = si->address;
+  normSect->alignment     = si->alignment;
+  // Record where normalized section is.
+  si->normalizedSectionIndex = file.sections.size()-1;
+  // Copy content from atoms to content buffer for section.
+  // FIXME: zerofill atoms/sections should not take up content space.
+  normSect->content.resize(si->size);
+  Hex8 *sectionContent = normSect->content.data();
+  for (AtomInfo &ai : si->atomsAndOffsets) {
+    // Copy raw bytes.
+    uint8_t *atomContent = reinterpret_cast<uint8_t*>
+                                          (&sectionContent[ai.offsetInSection]);
+    memcpy(atomContent, ai.atom->rawContent().data(), ai.atom->size());
+    // Apply fix-ups.
+    for (const Reference *ref : *ai.atom) {
+      uint32_t offset = ref->offsetInAtom();
+      uint64_t targetAddress = 0;
+      if ( ref->target() != nullptr )
+        targetAddress = _atomToAddress[ref->target()];
+      uint64_t fixupAddress = _atomToAddress[ai.atom] + offset;
+      _context.kindHandler().applyFixup(ref->kind(), ref->addend(),
+                                       &atomContent[offset], fixupAddress,
+                                       targetAddress);
+    }
+  }
+}
+
+void Util::copySections(NormalizedFile &file) {
+  file.sections.reserve(_sectionInfos.size());
+  // For final linked images, write sections grouped by segment.
+  if (_context.outputFileType() != llvm::MachO::MH_OBJECT) {
+    for (SegmentInfo *sgi : _segmentInfos) {
+      for (SectionInfo *si : sgi->sections) {
+        appendSection(si, file);
+      }
+    }
+  } else {
+    // Object files write sections in default order.
+    for (SectionInfo *si : _sectionInfos) {
+      appendSection(si, file);
+    }
+  }
+}
+
+void Util::copyEntryPointAddress(NormalizedFile &nFile) {
+  if (_context.outputTypeHasEntry()) {
+    nFile.entryAddress = _atomToAddress[_entryAtom];
+  }
+}
+
+void Util::buildAtomToAddressMap() {
+  DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+                   << "assign atom addresses:\n");
+  const bool lookForEntry = _context.outputTypeHasEntry();
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      _atomToAddress[info.atom] = sect->address + info.offsetInSection;
+      if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
+          (info.atom->size() != 0) &&
+          info.atom->name() == _context.entrySymbolName()) {
+        _entryAtom = info.atom;
+      }
+      DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
+              << "   address="
+              << llvm::format("0x%016X", _atomToAddress[info.atom])
+              << " atom=" << info.atom
+              << " name=" << info.atom->name() << "\n");
+    }
+  }
+}
+
+uint8_t Util::scopeBits(const DefinedAtom* atom) {
+  switch (atom->scope()) {
+  case Atom::scopeTranslationUnit:
+    return 0;
+  case Atom::scopeLinkageUnit:
+    return N_PEXT | N_EXT;
+  case Atom::scopeGlobal:
+    return N_EXT;
+  }
+}
+
+bool Util::AtomSorter::operator()(const AtomAndIndex &left, 
+                                  const AtomAndIndex &right) {
+  return (left.atom->name().compare(right.atom->name()) < 0);
+}
+
+ 
+bool Util::belongsInGlobalSymbolsSection(const DefinedAtom* atom) {
+  return (atom->scope() == Atom::scopeGlobal);
+}
+
+void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
+  // Mach-O symbol table has three regions: locals, globals, undefs.
+  
+  // Add all local (non-global) symbols in address order
+  std::vector<AtomAndIndex> globals;
+  globals.reserve(512);
+  for (SectionInfo *sect : _sectionInfos) {
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      if (!atom->name().empty()) {
+        if (belongsInGlobalSymbolsSection(atom)) {
+          AtomAndIndex ai = { atom, sect->finalSectionIndex };
+          globals.push_back(ai);
+        } else {
+          Symbol sym;
+          sym.name  = atom->name();
+          sym.type  = N_SECT; 
+          sym.scope = scopeBits(atom);
+          sym.sect  = sect->finalSectionIndex;
+          sym.desc  = 0;
+          sym.value = _atomToAddress[atom];
+          file.localSymbols.push_back(sym);
+        }
+      }
+    }
+  }
+  
+  // Sort global symbol alphabetically, then add to symbol table.
+  std::sort(globals.begin(), globals.end(), AtomSorter());
+  for (AtomAndIndex &ai : globals) {
+    Symbol sym;
+    sym.name  = ai.atom->name();
+    sym.type  = N_SECT; 
+    sym.scope = scopeBits(static_cast<const DefinedAtom*>(ai.atom));
+    sym.sect  = ai.index;
+    sym.desc  = 0;
+    sym.value = _atomToAddress[ai.atom];
+    file.globalSymbols.push_back(sym);
+  }
+  
+  
+  // Sort undefined symbol alphabetically, then add to symbol table.
+  std::vector<AtomAndIndex> undefs;
+  undefs.reserve(128);
+  for (const UndefinedAtom *atom : atomFile.undefined()) {
+    AtomAndIndex ai = { atom, 0 };
+    undefs.push_back(ai);
+  }
+  for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
+    AtomAndIndex ai = { atom, 0 };
+    undefs.push_back(ai);
+  }
+  std::sort(undefs.begin(), undefs.end(), AtomSorter());
+  const uint32_t start = file.globalSymbols.size() + file.localSymbols.size();
+  for (AtomAndIndex &ai : undefs) {
+    Symbol sym;
+    sym.name  = ai.atom->name();
+    sym.type  = N_UNDF; 
+    sym.scope = N_EXT;
+    sym.sect  = 0;
+    sym.desc  = 0;
+    sym.value = 0;
+    _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
+    file.undefinedSymbols.push_back(sym);
+  }
+}
+
+const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
+  for (const Reference *ref : *lpAtom) {
+    if (_context.kindHandler().isLazyTarget(ref->kind())) {
+      return ref->target();
+    }
+  }
+  return nullptr;
+}
+
+const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
+  for (const Reference *ref : *stubAtom) {
+    if (const Atom *ta = ref->target()) {
+      if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) {
+        const Atom *target = targetOfLazyPointer(lpAtom);
+        if (target)
+          return target;
+      }
+    }
+  }
+  return nullptr;
+}
+
+
+void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
+  for (SectionInfo *si : _sectionInfos) {
+    Section &normSect = file.sections[si->normalizedSectionIndex];
+    switch (si->type) {
+    case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        bool foundTarget = false;
+        for (const Reference *ref : *info.atom) {
+          const Atom *target = ref->target();
+          if (target) {
+            if (isa<const SharedLibraryAtom>(target)) {
+              uint32_t index = _atomToSymbolIndex[target];
+              normSect.indirectSymbols.push_back(index);
+              foundTarget = true;
+            } else {
+              normSect.indirectSymbols.push_back(
+                                            llvm::MachO::INDIRECT_SYMBOL_LOCAL);
+            }
+          }
+        }
+        if (!foundTarget) {
+          normSect.indirectSymbols.push_back(
+                                             llvm::MachO::INDIRECT_SYMBOL_ABS);
+        }
+      }
+      break;
+    case llvm::MachO::S_LAZY_SYMBOL_POINTERS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        const Atom *target = targetOfLazyPointer(info.atom);
+        if (target) {
+          uint32_t index = _atomToSymbolIndex[target];
+          normSect.indirectSymbols.push_back(index);
+        }
+      }
+      break;
+    case llvm::MachO::S_SYMBOL_STUBS:
+      for (const AtomInfo &info : si->atomsAndOffsets) {
+        const Atom *target = targetOfStub(info.atom);
+        if (target) {
+          uint32_t index = _atomToSymbolIndex[target];
+          normSect.indirectSymbols.push_back(index);
+        }
+      }
+      break;
+    default:
+      break;
+    }
+  }
+
+}
+
+void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
+  // Scan all imported symbols and build up list of dylibs they are from.
+  int ordinal = 1;
+  for (const SharedLibraryAtom *slAtom : atomFile.sharedLibrary()) {
+    StringRef loadPath = slAtom->loadName();
+    DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath);
+    if (pos == _dylibInfo.end()) {
+      DylibInfo info;
+      info.ordinal = ordinal++;
+      info.hasWeak = slAtom->canBeNullAtRuntime();
+      info.hasNonWeak = !info.hasWeak;
+      _dylibInfo[loadPath] = info;
+      DependentDylib depInfo;
+      depInfo.path = loadPath;
+      depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
+      nFile.dependentDylibs.push_back(depInfo);
+    } else {
+      if ( slAtom->canBeNullAtRuntime() )
+        pos->second.hasWeak = true;
+      else
+        pos->second.hasNonWeak = true;
+    }
+  }
+  // Automatically weak link dylib in which all symbols are weak (canBeNull).
+  for (DependentDylib &dep : nFile.dependentDylibs) {
+    DylibInfo &info = _dylibInfo[dep.path];
+    if (info.hasWeak && !info.hasNonWeak)
+      dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
+  }
+}
+
+
+int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
+  return _dylibInfo[sa->loadName()].ordinal;
+}
+
+void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
+                                                  uint64_t &segmentStartAddr) {
+  segmentIndex = 0;
+  for (const SegmentInfo *seg : _segmentInfos) {
+    if ((seg->address <= sect->address) 
+      && (seg->address+seg->size >= sect->address+sect->size)) {
+      segmentStartAddr = seg->address;
+      return;
+    }
+    ++segmentIndex;
+  }
+  llvm_unreachable("section not in any segment");
+}
+
+
+void Util::appendReloc(const DefinedAtom *atom, const Reference *ref, 
+                                                     Relocations &relocations) {
+  // TODO: convert Reference to normalized relocation
+}
+
+void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
+  if (_context.outputFileType() != llvm::MachO::MH_OBJECT)
+    return;
+  
+  for (SectionInfo *si : _sectionInfos) {
+    Section &normSect = file.sections[si->normalizedSectionIndex];
+    for (const AtomInfo &info : si->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      for (const Reference *ref : *atom) {
+        appendReloc(atom, ref, normSect.relocations);
+      }
+    }
+  }
+}
+
+void Util::addRebaseAndBindingInfo(const lld::File &atomFile, 
+                                                        NormalizedFile &nFile) {
+  if (_context.outputFileType() == llvm::MachO::MH_OBJECT)
+    return;
+
+  uint8_t segmentIndex;
+  uint64_t segmentStartAddr;
+  for (SectionInfo *sect : _sectionInfos) {
+    segIndexForSection(sect, segmentIndex, segmentStartAddr);
+    for (const AtomInfo &info : sect->atomsAndOffsets) {
+      const DefinedAtom *atom = info.atom;
+      for (const Reference *ref : *atom) {
+        uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom() 
+                                - segmentStartAddr;
+        const Atom* targ = ref->target();
+        if (_context.kindHandler().isPointer(ref->kind())) {
+          // A pointer to a DefinedAtom requires rebasing.
+          if (dyn_cast<DefinedAtom>(targ)) {
+            RebaseLocation rebase;
+            rebase.segIndex = segmentIndex;
+            rebase.segOffset = segmentOffset;
+            rebase.kind = llvm::MachO::REBASE_TYPE_POINTER;
+            nFile.rebasingInfo.push_back(rebase);
+          }
+          // A pointer to an SharedLibraryAtom requires binding.
+          if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
+            BindLocation bind;
+            bind.segIndex = segmentIndex;
+            bind.segOffset = segmentOffset;
+            bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+            bind.canBeNull = sa->canBeNullAtRuntime();
+            bind.ordinal = dylibOrdinal(sa);
+            bind.symbolName = targ->name(); 
+            bind.addend = ref->addend();
+            nFile.bindingInfo.push_back(bind);
+          }
+        }
+        if (_context.kindHandler().isLazyTarget(ref->kind())) {
+            BindLocation bind;
+            bind.segIndex = segmentIndex;
+            bind.segOffset = segmentOffset;
+            bind.kind = llvm::MachO::BIND_TYPE_POINTER;
+            bind.canBeNull = false; //sa->canBeNullAtRuntime();
+            bind.ordinal = 1;
+            bind.symbolName = targ->name(); 
+            bind.addend = ref->addend();
+            nFile.lazyBindingInfo.push_back(bind);
+        }
+      }
+    }
+  }
+}
+
+uint32_t Util::fileFlags() {
+  return 0;  //FIX ME
+}
+
+} // end anonymous namespace
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Convert a set of Atoms into a normalized mach-o file.
+ErrorOr<std::unique_ptr<NormalizedFile>> 
+normalizedFromAtoms(const lld::File &atomFile, 
+                                           const MachOLinkingContext &context) {
+  // The util object buffers info until the normalized file can be made. 
+  Util util(context);
+  util.assignAtomsToSections(atomFile);
+  util.organizeSections();
+  util.assignAddressesToSections();
+  util.buildAtomToAddressMap();
+  
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+  NormalizedFile &normFile = *f.get();
+  f->arch = context.arch();
+  f->fileType = context.outputFileType();
+  f->flags = util.fileFlags();
+  util.copySegmentInfo(normFile);
+  util.copySections(normFile);
+  util.addDependentDylibs(atomFile, normFile);
+  util.addSymbols(atomFile, normFile);
+  util.addIndirectSymbols(atomFile, normFile);
+  util.addRebaseAndBindingInfo(atomFile, normFile);
+  util.addSectionRelocs(atomFile, normFile);
+  util.copyEntryPointAddress(normFile);
+ 
+  return std::move(f);
+}
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp Wed Nov  6 15:36:55 2013
@@ -37,43 +37,9 @@
 using llvm::StringRef;
 using llvm::error_code;
 using llvm::dyn_cast;
-
-using llvm::yaml::MappingTraits;
-using llvm::yaml::SequenceTraits;
-using llvm::yaml::ScalarEnumerationTraits;
-using llvm::yaml::ScalarBitSetTraits;
-using llvm::yaml::ScalarTraits;
-using llvm::yaml::IO;
-using llvm::yaml::Hex64;
-using llvm::yaml::Hex32;
-using llvm::yaml::Hex8;
-
-using llvm::MachO::HeaderFileType;
-using llvm::MachO::RebaseType;
-using llvm::MachO::BindType;
-using llvm::MachO::NListType;
-using llvm::MachO::RelocationInfoType;
-using llvm::MachO::SectionType;
-using llvm::MachO::LoadCommandType;
-
-using lld::mach_o::normalized::Section;
-using lld::mach_o::normalized::Symbol;
-using lld::mach_o::normalized::Relocation;
-using lld::mach_o::normalized::Relocations;
-using lld::mach_o::normalized::IndirectSymbols;
-using lld::mach_o::normalized::ContentBytes;
-using lld::mach_o::normalized::FileFlags;
-using lld::mach_o::normalized::SectionAttr;
-using lld::mach_o::normalized::SymbolScope;
-using lld::mach_o::normalized::SymbolDesc;
-using lld::mach_o::normalized::VMProtect;
-using lld::mach_o::normalized::Segment;
-using lld::mach_o::normalized::DependentDylib;
-using lld::mach_o::normalized::RebaseLocation;
-using lld::mach_o::normalized::BindLocation;
-using lld::mach_o::normalized::ExportFlags;
-using lld::mach_o::normalized::Export;
-using lld::mach_o::normalized::NormalizedFile;
+using namespace llvm::yaml;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
 
 
 LLVM_YAML_IS_SEQUENCE_VECTOR(Segment);

Modified: lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp Wed Nov  6 15:36:55 2013
@@ -12,1488 +12,51 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/Format.h"
+#include "llvm/Support/MachO.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/system_error.h"
 
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-
-#include "lld/Core/DefinedAtom.h"
 #include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-#include "lld/Core/SharedLibraryAtom.h"
 #include "lld/ReaderWriter/MachOLinkingContext.h"
-#include "lld/ReaderWriter/MachOFormat.hpp"
 
-#include <vector>
-#include <map>
-#include <string.h>
 
-#include "ReferenceKinds.h"
+#include "MachONormalizedFile.h"
 #include "ExecutableAtoms.hpp"
 
+using lld::mach_o::normalized::NormalizedFile;
+
 namespace lld {
 namespace mach_o {
-class LoadCommandPaddingChunk;
-class SymbolStringsChunk;
-class MachOWriter;
-
-//
-// A mach-o file consists of some meta data (header and load commands),
-// then atom content (e.g. function instructions), then more meta data
-// (symbol table, etc).  Before you can write a mach-o file, you need to
-// compute what will be the file offsets and "addresses" of various things
-// in the file.
-//
-// The design here is to break up what will be the mach-o file into chunks.
-// Each Chunk has an object to manage its size and content.  There is a
-// chunk for the mach_header, one for the load commands, and one for each
-// part of the LINKEDIT segment.  There is also one chunk for each traditional
-// mach-o section.  The MachOWriter manages the list of chunks.  And
-// asks each to determine its size in the correct order.  Many chunks
-// cannot be sized until other chunks are sized (e.g. the dyld info
-// in the LINKEDIT cannot be sized until all atoms have been assigned
-// addresses).
-//
-// Once all chunks have a size, the MachOWriter iterates through them and
-// asks each to write out their content.
-//
-
-
-
-//
-// A Chunk is an abstrace contiguous range of a generated
-// mach-o executable file.
-//
-class Chunk {
-public:
-  virtual             ~Chunk() { }
-  virtual StringRef   segmentName() const = 0;
-  virtual bool        occupiesNoDiskSpace();
-  virtual void        write(uint8_t *fileBuffer) = 0;
-  void                assignFileOffset(uint64_t &curOff, uint64_t &curAddr);
-  virtual const char* info() = 0;
-  uint64_t            size() const;
-  uint64_t            address() const;
-  uint64_t            fileOffset() const;
-  uint64_t            align2() const;
-  static uint64_t     alignTo(uint64_t value, uint8_t align2);
-
-protected:
-                      Chunk();
-
-  uint64_t            _size;
-  uint64_t            _address;
-  uint64_t            _fileOffset;
-  uint32_t            _align2;
-};
-
-
-
-//
-// A SectionChunk represents a set of Atoms assigned to a specific
-// mach-o section (which is a subrange of a mach-o segment).
-// For example, there is one SectionChunk for the __TEXT,__text section.
-//
-class SectionChunk : public Chunk {
-public:
-  static SectionChunk*  make(DefinedAtom::ContentType,
-                             MachOWriter &writer);
-  virtual StringRef     segmentName() const;
-  virtual bool          occupiesNoDiskSpace();
-  virtual void          write(uint8_t *fileBuffer);
-  virtual const char*   info();
-  StringRef             sectionName();
-  uint32_t              flags() const;
-  uint32_t              permissions();
-  void                  appendAtom(const DefinedAtom*);
-
-  struct AtomInfo {
-    const DefinedAtom  *atom;
-    uint64_t            offsetInSection;
-  };
-
-  const std::vector<AtomInfo>& atoms() const;
-
-private:
-                SectionChunk(StringRef seg,
-                             StringRef sect,
-                             uint32_t flags,
-                             MachOWriter &writer);
-
-  StringRef                 _segmentName;
-  StringRef                 _sectionName;
-  MachOWriter              &_writer;
-  uint32_t                  _flags;
-  uint32_t                  _permissions;
-  std::vector<AtomInfo>     _atoms;
-};
-
-
-
-//
-// A MachHeaderChunk represents the mach_header struct at the start
-// of a mach-o executable file.
-//
-class MachHeaderChunk : public Chunk {
-public:
-  MachHeaderChunk(const MachOLinkingContext &context, const File &file);
-  virtual StringRef segmentName() const;
-  virtual void          write(uint8_t *fileBuffer);
-  virtual const char*   info();
-  void                  recordLoadCommand(load_command*);
-  uint64_t              loadCommandsSize();
-
-private:
-  uint32_t              magic(uint32_t cpuType);
-
-  mach_header               _mh;
-};
-
-
-
-//
-// A LoadCommandsChunk represents the variable length list of
-// of load commands in a mach-o executable file right after the
-// mach_header.
-//
-class LoadCommandsChunk : public Chunk {
-public:
-  LoadCommandsChunk(MachHeaderChunk &, const MachOLinkingContext &,
-                    MachOWriter &);
-  virtual StringRef segmentName() const;
-  virtual void        write(uint8_t *fileBuffer);
-  virtual const char* info();
-  void                computeSize(const lld::File &file);
-  void                addSection(SectionChunk*);
-  void                updateLoadCommandContent(const lld::File &file);
-
-private:
-  friend LoadCommandPaddingChunk;
-
-  void                addLoadCommand(load_command* lc);
-  void                setMachOSection(SectionChunk *chunk,
-                                      segment_command *seg, uint32_t index);
-  uint32_t            permissionsFromSections(
-                                  const SmallVector<SectionChunk*,16> &);
-  bool                use64BitMachO() const;
-
-  struct ChunkSegInfo {
-    SectionChunk       *chunk;
-    segment_command    *segment;
-    section_64         *section;
-  };
-
-  MachHeaderChunk             &_mh;
-  const MachOLinkingContext &_context;
-  MachOWriter &_writer;
-  segment_command *_linkEditSegment;
-  symtab_command              *_symbolTableLoadCommand;
-  entry_point_command         *_entryPointLoadCommand;
-  thread_command              *_threadLoadCommand;
-  dyld_info_command           *_dyldInfoLoadCommand;
-  std::vector<load_command*>   _loadCmds;
-  std::vector<ChunkSegInfo>    _sectionInfo;
-  llvm::StringMap<uint32_t>    _dylibNamesToOrdinal;
-};
-
-
-
-//
-// A LoadCommandPaddingChunk represents the padding space between the last
-// load commmand and the first section (usually __text) in the __TEXT
-// segment.
-//
-class LoadCommandPaddingChunk : public Chunk {
-public:
-                      LoadCommandPaddingChunk(LoadCommandsChunk&);
-  virtual StringRef   segmentName() const;
-  virtual void        write(uint8_t *fileBuffer);
-  virtual const char* info();
-  void                computeSize();
-private:
-  LoadCommandsChunk&  _loadCommandsChunk;
-};
-
-
-
-//
-// LinkEditChunk is the base class for all chunks in the
-// __LINKEDIT segment at the end of a mach-o executable.
-//
-class LinkEditChunk : public Chunk {
-public:
-                      LinkEditChunk();
-  virtual StringRef   segmentName() const;
-  virtual void        computeSize(const lld::File &file,
-                                      const std::vector<SectionChunk*>&) = 0;
-};
-
-
-
-//
-// A DyldInfoChunk represents the bytes for any of the dyld info areas
-// in the __LINKEDIT segment at the end of a mach-o executable.
-//
-class DyldInfoChunk : public LinkEditChunk {
-public:
-                      DyldInfoChunk(MachOWriter &);
-  virtual void        write(uint8_t *fileBuffer);
 
-protected:
-  void                append_byte(uint8_t);
-  void                append_uleb128(uint64_t);
-  void                append_string(StringRef);
-
-  MachOWriter            &_writer;
-  std::vector<uint8_t>    _bytes;
-};
-
-
-
-//
-// A BindingInfoChunk represents the bytes containing binding info
-// in the __LINKEDIT segment at the end of a mach-o executable.
-//
-class BindingInfoChunk : public DyldInfoChunk {
-public:
-                      BindingInfoChunk(MachOWriter &);
-  virtual void        computeSize(const lld::File &file,
-                                      const std::vector<SectionChunk*>&);
-  virtual const char* info();
-};
-
-
-
-//
-// A LazyBindingInfoChunk represents the bytes containing lazy binding info
-// in the __LINKEDIT segment at the end of a mach-o executable.
-//
-class LazyBindingInfoChunk : public DyldInfoChunk {
-public:
-                      LazyBindingInfoChunk(MachOWriter &);
-  virtual void        computeSize(const lld::File &file,
-                                      const std::vector<SectionChunk*>&);
-  virtual const char* info();
-private:
-  void                 updateHelper(const DefinedAtom *, uint32_t );
-};
-
-
-//
-// A SymbolTableChunk represents the array of nlist structs in the
-// __LINKEDIT segment at the end of a mach-o executable.
-//
-class SymbolTableChunk : public LinkEditChunk {
-public:
-                      SymbolTableChunk(SymbolStringsChunk&, MachOWriter&);
-  virtual void        write(uint8_t *fileBuffer);
-  virtual void        computeSize(const lld::File &file,
-                                      const std::vector<SectionChunk*>&);
-  virtual const char* info();
-  uint32_t            count();
-
-private:
-  uint8_t             nType(const DefinedAtom*);
-
-  MachOWriter           &_writer;
-  SymbolStringsChunk    &_stringsChunk;
-  std::vector<nlist>     _globalDefinedsymbols;
-  std::vector<nlist>     _localDefinedsymbols;
-  std::vector<nlist>     _undefinedsymbols;
-};
-
-
-//
-// A SymbolStringsChunk represents the strings pointed to
-// by nlist structs in the __LINKEDIT segment at the end
-// of a mach-o executable.
-//
-class SymbolStringsChunk : public LinkEditChunk {
-public:
-                      SymbolStringsChunk();
-  virtual void        write(uint8_t *fileBuffer);
-  virtual void        computeSize(const lld::File &file,
-                                      const std::vector<SectionChunk*>&);
-  virtual const char* info();
-  uint32_t            stringIndex(StringRef);
-
-private:
-  std::vector<char>         _strings;
-};
-
-
-//
-// A MachOWriter manages all the Chunks that comprise a mach-o executable.
-//
 class MachOWriter : public Writer {
 public:
-  MachOWriter(const MachOLinkingContext &context);
-
-  virtual error_code  writeFile(const lld::File &file, StringRef path);
-  virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
-
-  uint64_t    addressOfAtom(const Atom *atom);
-  void        findSegment(StringRef segmentName, uint32_t *segIndex,
-                                uint64_t *segStartAddr, uint64_t *segEndAddr);
-
-  const std::vector<Chunk*> chunks() { return _chunks; }
-  mach_o::KindHandler &kindHandler() { return _referenceKindHandler; }
-
-  bool use64BitMachO() const;
-
-private:
-  friend LoadCommandsChunk;
-  friend LazyBindingInfoChunk;
-  friend BindingInfoChunk;
-
-  void        build(const lld::File &file);
-  void        createChunks(const lld::File &file);
-  void        buildAtomToAddressMap();
-  void        assignFileOffsets();
-  void        addLinkEditChunk(LinkEditChunk *chunk);
-  void        buildLinkEdit(const lld::File &file);
-  void        assignLinkEditFileOffsets();
-  void        dump();
-
-
-  typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
-
-  const MachOLinkingContext &_context;
-  mach_o::KindHandler &_referenceKindHandler;
-  std::unique_ptr<CRuntimeFile> _cRuntimeFile;
-  LoadCommandsChunk *_loadCommandsChunk;
-  LoadCommandPaddingChunk *_paddingChunk;
-  AtomToAddress _atomToAddress;
-  std::vector<Chunk *> _chunks;
-  std::vector<SectionChunk *> _sectionChunks;
-  std::vector<LinkEditChunk *> _linkEditChunks;
-  BindingInfoChunk *_bindingInfo;
-  LazyBindingInfoChunk       *_lazyBindingInfo;
-  SymbolTableChunk           *_symbolTableChunk;
-  SymbolStringsChunk         *_stringsChunk;
-  const DefinedAtom          *_entryAtom;
-  uint64_t                    _linkEditStartOffset;
-  uint64_t                    _linkEditStartAddress;
-};
-
-
-
-//===----------------------------------------------------------------------===//
-//  Chunk
-//===----------------------------------------------------------------------===//
-
-Chunk::Chunk()
- : _size(0), _address(0), _fileOffset(0), _align2(0) {
-}
-
-bool Chunk::occupiesNoDiskSpace() {
-  return false;
-}
-
-uint64_t Chunk::size() const {
-  return _size;
-}
-
-uint64_t Chunk::align2() const {
-  return _align2;
-}
-
-uint64_t Chunk::address() const {
-  return _address;
-}
-
-uint64_t Chunk::fileOffset() const {
-  return _fileOffset;
-}
-
-uint64_t Chunk::alignTo(uint64_t value, uint8_t align2) {
-  uint64_t align = 1 << align2;
-  return ( (value + (align-1)) & (-align) );
-}
-
-void Chunk::assignFileOffset(uint64_t &curOffset, uint64_t &curAddress) {
-  if ( this->occupiesNoDiskSpace() ) {
-    // FileOffset does not change, but address space does change.
-    uint64_t alignedAddress = alignTo(curAddress, _align2);
-   _address = alignedAddress;
-   curAddress = alignedAddress + _size;
-  }
-  else {
-    // FileOffset and address both move by _size amount after alignment.
-    uint64_t alignPadding = alignTo(curAddress, _align2) - curAddress;
-    _fileOffset = curOffset + alignPadding;
-    _address = curAddress + alignPadding;
-    curOffset = _fileOffset + _size;
-    curAddress = _address + _size;
-  }
-
-  DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
-                      << "   fileOffset="
-                      << llvm::format("0x%08X", _fileOffset)
-                      << " address="
-                      << llvm::format("0x%016X", _address)
-                      << " info=" << this->info() << "\n");
-}
-
-
-
-//===----------------------------------------------------------------------===//
-//  SectionChunk
-//===----------------------------------------------------------------------===//
-
-SectionChunk::SectionChunk(StringRef seg, StringRef sect,
-                           uint32_t flags, MachOWriter &writer)
- : _segmentName(seg), _sectionName(sect), _writer(writer),
-   _flags(flags), _permissions(0) {
-
-}
-
-SectionChunk* SectionChunk::make(DefinedAtom::ContentType type,
-                                 MachOWriter &writer) {
-  switch ( type ) {
-    case DefinedAtom::typeCode:
-      return new SectionChunk("__TEXT", "__text",
-                              S_REGULAR | S_ATTR_PURE_INSTRUCTIONS, writer);
-      break;
-    case DefinedAtom::typeCString:
-       return new SectionChunk("__TEXT", "__cstring",
-                               S_CSTRING_LITERALS, writer);
-       break;
-    case DefinedAtom::typeStub:
-      return new SectionChunk("__TEXT", "__stubs",
-                              S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS, writer);
-      break;
-    case DefinedAtom::typeStubHelper:
-      return new SectionChunk("__TEXT", "__stub_helper",
-                              S_REGULAR | S_ATTR_PURE_INSTRUCTIONS, writer);
-      break;
-    case DefinedAtom::typeLazyPointer:
-      return new SectionChunk("__DATA", "__la_symbol_ptr",
-                              S_LAZY_SYMBOL_POINTERS, writer);
-      break;
-    case DefinedAtom::typeGOT:
-      return new SectionChunk("__DATA", "__got",
-                              S_NON_LAZY_SYMBOL_POINTERS, writer);
-      break;
-    default:
-      assert(0 && "TO DO: add support for more sections");
-      break;
-  }
-  return nullptr;
-}
-
-bool SectionChunk::occupiesNoDiskSpace() {
-  return ( (_flags & SECTION_TYPE) == S_ZEROFILL );
-}
-
-StringRef SectionChunk::segmentName() const {
-  return _segmentName;
-}
-
-StringRef SectionChunk::sectionName() {
-  return _sectionName;
-}
-
-uint32_t SectionChunk::flags() const {
-  return _flags;
-}
-
-uint32_t SectionChunk::permissions() {
-  return _permissions;
-}
-
-const char* SectionChunk::info() {
-  return _sectionName.data();
-}
-
-const std::vector<SectionChunk::AtomInfo>& SectionChunk::atoms() const {
-  return _atoms;
-}
-
-void SectionChunk::appendAtom(const DefinedAtom *atom) {
-  // Figure out offset for atom in this section given alignment constraints.
-  uint64_t offset = _size;
-  DefinedAtom::Alignment atomAlign = atom->alignment();
-  uint64_t align2 = 1 << atomAlign.powerOf2;
-  uint64_t requiredModulus = atomAlign.modulus;
-  uint64_t currentModulus = (offset % align2);
-  if ( currentModulus != requiredModulus ) {
-    if ( requiredModulus > currentModulus )
-      offset += requiredModulus-currentModulus;
-    else
-      offset += align2+requiredModulus-currentModulus;
-  }
-  // Record max alignment of any atom in this section.
-  if ( align2 > _align2 )
-    _align2 = align2;
-  // Assign atom to this section with this offset.
-  SectionChunk::AtomInfo ai = {atom, offset};
-  _atoms.push_back(ai);
-  // Update section size to include this atom.
-  _size = offset + atom->size();
-  // Update permissions
-  DefinedAtom::ContentPermissions perms = atom->permissions();
-  if ( (perms & DefinedAtom::permR__) == DefinedAtom::permR__ )
-    _permissions |= VM_PROT_READ;
-  if ( (perms & DefinedAtom::permRW_) == DefinedAtom::permRW_ )
-    _permissions |= VM_PROT_WRITE;
-  if ( (perms & DefinedAtom::permR_X) == DefinedAtom::permR_X )
-    _permissions |= VM_PROT_EXECUTE;
-}
-
-
-void SectionChunk::write(uint8_t *chunkBuffer) {
-  // Each section's content is just its atoms' content.
-  for (const AtomInfo &atomInfo : _atoms ) {
-    // Copy raw content of atom to file buffer.
-    ArrayRef<uint8_t> content = atomInfo.atom->rawContent();
-    uint64_t contentSize = content.size();
-    if ( contentSize == 0 )
-      continue;
-    uint8_t* atomContent = chunkBuffer + atomInfo.offsetInSection;
-    ::memcpy(atomContent, content.data(), contentSize);
-    // Apply fixups to file buffer
-    for (const Reference *ref : *atomInfo.atom) {
-      uint32_t offset = ref->offsetInAtom();
-      uint64_t targetAddress = 0;
-      if ( ref->target() != nullptr )
-        targetAddress = _writer.addressOfAtom(ref->target());
-      uint64_t fixupAddress = _writer.addressOfAtom(atomInfo.atom) + offset;
-      _writer.kindHandler().applyFixup(ref->kind(), ref->addend(),
-                                       &atomContent[offset], fixupAddress,
-                                       targetAddress);
-    }
-  }
-}
-
-
-//===----------------------------------------------------------------------===//
-//  MachHeaderChunk
-//===----------------------------------------------------------------------===//
-
-MachHeaderChunk::MachHeaderChunk(const MachOLinkingContext &context,
-                                 const File &file) {
-  // Set up mach_header based on options
-  _mh.magic = this->magic(context.getCPUType());
-  _mh.cputype = context.getCPUType();
-  _mh.cpusubtype = context.getCPUSubType();
-  _mh.filetype = context.outputFileType();
-  _mh.ncmds = 0;
-  _mh.sizeofcmds = 0;
-  _mh.flags      = 0;
-  _mh.reserved   = 0;
-
-  _size = _mh.size();
-}
-
-
-StringRef MachHeaderChunk::segmentName() const {
-  return StringRef("__TEXT");
-}
-
-void MachHeaderChunk::write(uint8_t *chunkBuffer) {
-  _mh.copyTo(chunkBuffer);
-}
-
-const char* MachHeaderChunk::info() {
-  return "mach_header";
-}
-
-void MachHeaderChunk::recordLoadCommand(load_command* lc) {
-  _mh.recordLoadCommand(lc);
-}
-
-uint64_t MachHeaderChunk::loadCommandsSize() {
-  return _mh.sizeofcmds;
-}
-
-uint32_t MachHeaderChunk::magic(uint32_t cpuType) {
-  switch ( cpuType ) {
-    case CPU_TYPE_ARM:
-    case CPU_TYPE_I386:
-      return MH_MAGIC;
-    case CPU_TYPE_X86_64:
-      return MH_MAGIC_64;
-  }
-  llvm_unreachable("file CPU type not supported");
-  return 0;
-}
-
-
-
-//===----------------------------------------------------------------------===//
-//  LoadCommandsChunk
-//===----------------------------------------------------------------------===//
-
-LoadCommandsChunk::LoadCommandsChunk(MachHeaderChunk &mh,
-                                     const MachOLinkingContext &context,
-                                     MachOWriter &writer)
-    : _mh(mh), _context(context), _writer(writer), _linkEditSegment(nullptr),
-      _symbolTableLoadCommand(nullptr), _entryPointLoadCommand(nullptr),
-      _threadLoadCommand(nullptr), _dyldInfoLoadCommand(nullptr) {}
-
-StringRef LoadCommandsChunk::segmentName() const {
-  return StringRef("__TEXT");
-}
-
-void LoadCommandsChunk::write(uint8_t *chunkBuffer) {
-  uint8_t* p = chunkBuffer;
-  for ( load_command* lc : _loadCmds ) {
-    assert( ((uintptr_t)p & 0x3) == 0);
-    lc->copyTo(p);
-    p += lc->cmdsize;
-  }
-}
-
-const char* LoadCommandsChunk::info() {
-  return "load commands";
-}
-
-void LoadCommandsChunk::setMachOSection(SectionChunk *chunk,
-                                    segment_command *seg, uint32_t index) {
-  for (ChunkSegInfo &entry : _sectionInfo) {
-    if ( entry.chunk == chunk ) {
-      entry.section = &(seg->sections[index]);
-      entry.segment = seg;
-      return;
-    }
-  }
-  assert(0 && "setMachOSection() chunk not found");
-}
-
-uint32_t LoadCommandsChunk::permissionsFromSections(
-                        const SmallVector<SectionChunk*,16> &sections) {
-  uint32_t result = 0;
-  for (SectionChunk *chunk : sections) {
-    result |= chunk->permissions();
-  }
-  return result;
-}
-
-void LoadCommandsChunk::computeSize(const lld::File &file) {
-  const bool is64 = _writer.use64BitMachO();
-  // Main executables have a __PAGEZERO segment.
-  uint64_t pageZeroSize = _context.pageZeroSize();
-  if (pageZeroSize != 0) {
-    assert(is64 || (pageZeroSize < 0xFFFFFFFF));
-    segment_command* pzSegCmd = new segment_command(0, is64);
-    strcpy(pzSegCmd->segname, "__PAGEZERO");
-    pzSegCmd->vmaddr   = 0;
-    pzSegCmd->vmsize   = pageZeroSize;
-    pzSegCmd->fileoff  = 0;
-    pzSegCmd->filesize = 0;
-    pzSegCmd->maxprot  = 0;
-    pzSegCmd->initprot = 0;
-    pzSegCmd->nsects   = 0;
-    pzSegCmd->flags    = 0;
-    this->addLoadCommand(pzSegCmd);
-  }
-  // Add other segment load commands
-  StringRef lastSegName = StringRef("__TEXT");
-  SmallVector<SectionChunk*,16> sections;
-  for (ChunkSegInfo &entry : _sectionInfo) {
-    StringRef entryName = entry.chunk->segmentName();
-    if ( !lastSegName.equals(entryName) ) {
-      // Start of new segment, so create load command for all previous sections.
-      segment_command* segCmd = new segment_command(sections.size(), is64);
-      strncpy(segCmd->segname, lastSegName.data(), 16);
-      segCmd->initprot = this->permissionsFromSections(sections);
-      segCmd->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
-      this->addLoadCommand(segCmd);
-      unsigned int index = 0;
-      for (SectionChunk *chunk : sections) {
-        this->setMachOSection(chunk, segCmd, index);
-        ++index;
-      }
-      // Reset to begin new segment.
-      sections.clear();
-      lastSegName = entryName;
-    }
-    sections.push_back(entry.chunk);
-  }
-  // Add last segment load command.
-  segment_command* segCmd = new segment_command(sections.size(), is64);
-  strncpy(segCmd->segname, lastSegName.data(), 16);
-  segCmd->initprot = this->permissionsFromSections(sections);;
-  segCmd->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
-  this->addLoadCommand(segCmd);
-  unsigned int index = 0;
-  for (SectionChunk *chunk : sections) {
-    this->setMachOSection(chunk, segCmd, index);
-    ++index;
-  }
-
-  // Add LINKEDIT segment load command
-  _linkEditSegment = new segment_command(0, is64);
-  strcpy(_linkEditSegment->segname, "__LINKEDIT");
-  _linkEditSegment->initprot = VM_PROT_READ;
-  _linkEditSegment->maxprot = VM_PROT_READ;
-  this->addLoadCommand(_linkEditSegment);
-
-  // Add dyld load command.
-  this->addLoadCommand(new dylinker_command("/usr/lib/dyld", is64));
-
-  // Add dylib load commands.
-  for (const SharedLibraryAtom* shlibAtom : file.sharedLibrary() ) {
-    StringRef installName = shlibAtom->loadName();
-    if ( _dylibNamesToOrdinal.count(installName) == 0 ) {
-      uint32_t ord = _dylibNamesToOrdinal.size();
-      _dylibNamesToOrdinal[installName] = ord;
-    }
-  }
-  for (llvm::StringMap<uint32_t>::iterator it=_dylibNamesToOrdinal.begin(),
-                            end=_dylibNamesToOrdinal.end(); it != end; ++it) {
-    this->addLoadCommand(new dylib_command(it->first(), is64));
-  }
-
-  // Add symbol table load command
-  _symbolTableLoadCommand = new symtab_command(is64);
-  this->addLoadCommand(_symbolTableLoadCommand);
-
-  // Add dyld info load command
-  _dyldInfoLoadCommand = new dyld_info_command(is64);
-  this->addLoadCommand(_dyldInfoLoadCommand);
-
-  // Add entry point load command to main executables
-  if (_context.addEntryPointLoadCommand()) {
-    _entryPointLoadCommand = new entry_point_command(is64);
-    this->addLoadCommand(_entryPointLoadCommand);
-  } else if (_context.addUnixThreadLoadCommand()) {
-    _threadLoadCommand = new thread_command(_context.getCPUType(), is64);
-    this->addLoadCommand(_threadLoadCommand);
-  }
-
-  // Compute total size.
-  _size = _mh.loadCommandsSize();
-}
-
-
-void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) {
-  // Update segment/section information in segment load commands
-  segment_command *lastSegment = nullptr;
-  for (ChunkSegInfo &entry : _sectionInfo) {
-    // Set section info.
-    ::strncpy(entry.section->sectname, entry.chunk->sectionName().data(), 16);
-    ::strncpy(entry.section->segname, entry.chunk->segmentName().data(), 16);
-    entry.section->addr   = entry.chunk->address();
-    entry.section->size   = entry.chunk->size();
-    entry.section->offset = entry.chunk->fileOffset();
-    entry.section->align  = entry.chunk->align2();
-    entry.section->reloff = 0;
-    entry.section->nreloc = 0;
-    entry.section->flags  = entry.chunk->flags();
-    // Adjust segment info if needed.
-    if ( entry.segment != lastSegment ) {
-      // This is first section in segment.
-      if ( strcmp(entry.segment->segname, "__TEXT") == 0 ) {
-        // __TEXT segment is special need mach_header section.
-        entry.segment->vmaddr = _writer._chunks.front()->address();
-        entry.segment->fileoff = _writer._chunks.front()->fileOffset();
-      }
-      else {
-        entry.segment->vmaddr  = entry.chunk->address();
-        entry.segment->fileoff = entry.chunk->fileOffset();
-      }
-
-      lastSegment = entry.segment;
-    }
-    uint64_t sectionEndAddr = entry.section->addr + entry.section->size;
-    if ( entry.segment->vmaddr + entry.segment->vmsize < sectionEndAddr) {
-      uint64_t sizeToEndOfSection = sectionEndAddr - entry.segment->vmaddr;
-      entry.segment->vmsize = alignTo(sizeToEndOfSection, 12);
-      // zero-fill sections do not increase the segment's filesize
-      if ( ! entry.chunk->occupiesNoDiskSpace() ) {
-        entry.segment->filesize = alignTo(sizeToEndOfSection, 12);
-      }
-    }
-  }
-  uint64_t linkEditSize = _writer._stringsChunk->fileOffset()
-                        + _writer._stringsChunk->size()
-                        - _writer._linkEditStartOffset;
-  _linkEditSegment->vmaddr   = _writer._linkEditStartAddress;
-  _linkEditSegment->vmsize   = alignTo(linkEditSize,12);
-  _linkEditSegment->fileoff  = _writer._linkEditStartOffset;
-  _linkEditSegment->filesize = linkEditSize;
-
-  // Update dyld_info load command.
-  _dyldInfoLoadCommand->bind_off       = _writer._bindingInfo->fileOffset();
-  _dyldInfoLoadCommand->bind_size      = _writer._bindingInfo->size();
-  _dyldInfoLoadCommand->lazy_bind_off  = _writer._lazyBindingInfo->fileOffset();
-  _dyldInfoLoadCommand->lazy_bind_size = _writer._lazyBindingInfo->size();
-
-
-  // Update symbol table load command.
-  _symbolTableLoadCommand->symoff  = _writer._symbolTableChunk->fileOffset();
-  _symbolTableLoadCommand->nsyms   = _writer._symbolTableChunk->count();
-  _symbolTableLoadCommand->stroff  = _writer._stringsChunk->fileOffset();
-  _symbolTableLoadCommand->strsize = _writer._stringsChunk->size();
-
-  // Update entry point
-  if ( _entryPointLoadCommand != nullptr ) {
-    const Atom *mainAtom = _writer._entryAtom;
-    assert(mainAtom != nullptr);
-    uint32_t entryOffset = _writer.addressOfAtom(mainAtom) - _mh.address();
-    _entryPointLoadCommand->entryoff = entryOffset;
-  }
-  else if ( _threadLoadCommand != nullptr ) {
-    const Atom *startAtom = _writer._entryAtom;
-    assert(startAtom != nullptr);
-    _threadLoadCommand->setPC(_writer.addressOfAtom(startAtom));
-  }
-
-}
-
-
-void LoadCommandsChunk::addSection(SectionChunk* chunk) {
-  LoadCommandsChunk::ChunkSegInfo csi = {chunk, nullptr, nullptr};
-  _sectionInfo.push_back(csi);
-}
-
-void LoadCommandsChunk::addLoadCommand(load_command* lc) {
-  _mh.recordLoadCommand(lc);
-  _loadCmds.push_back(lc);
-}
-
-
-
-//===----------------------------------------------------------------------===//
-//  LoadCommandPaddingChunk
-//===----------------------------------------------------------------------===//
-
-LoadCommandPaddingChunk::LoadCommandPaddingChunk(LoadCommandsChunk& lcc)
-  : _loadCommandsChunk(lcc) {
-}
-
-StringRef LoadCommandPaddingChunk::segmentName() const {
-  return StringRef("__TEXT");
-}
-
-void LoadCommandPaddingChunk::write(uint8_t *chunkBuffer) {
-  // Zero fill padding.
-}
-
-const char* LoadCommandPaddingChunk::info() {
-  return "padding";
-}
-
-// Segments are page sized.  Normally, any extra space not used by atoms
-// is put at the end of the last page.  But the __TEXT segment is special.
-// Any extra space is put between the load commands and the first section.
-// The padding is put there to allow the load commands to be
-// post-processed which might potentially grow them.
-void LoadCommandPaddingChunk::computeSize() {
- // Layout __TEXT sections backwards from end of page to get padding up front.
-  uint64_t addr = 0;
-  std::vector<LoadCommandsChunk::ChunkSegInfo>& sects
-                                        = _loadCommandsChunk._sectionInfo;
-  for (auto it=sects.rbegin(), end=sects.rend(); it != end; ++it) {
-    LoadCommandsChunk::ChunkSegInfo &entry = *it;
-    if ( !entry.chunk->segmentName().equals("__TEXT") )
-      continue;
-    addr -= entry.chunk->size();
-    addr = addr & (0 - (1 << entry.chunk->align2()));
-  }
-  // Subtract out size of mach_header and all load commands.
-  addr -= _loadCommandsChunk._mh.size();
-  addr -= _loadCommandsChunk.size();
-  // Modulo page size to get padding needed between load commands
-  // and first section.
-  _size = (addr % 4096);
-}
-
-//===----------------------------------------------------------------------===//
-//  LinkEditChunk
-//===----------------------------------------------------------------------===//
-
-LinkEditChunk::LinkEditChunk() {
-  _align2 = 3;
-}
-
-StringRef LinkEditChunk::segmentName() const {
-  return StringRef("__LINKEDIT");
-}
-
-
-//===----------------------------------------------------------------------===//
-//  DyldInfoChunk
-//===----------------------------------------------------------------------===//
-DyldInfoChunk::DyldInfoChunk(MachOWriter &writer)
- : _writer(writer) {
-}
-
-void DyldInfoChunk::write(uint8_t *chunkBuffer) {
-  ::memcpy(chunkBuffer, &_bytes[0], _bytes.size());
-}
-
-void DyldInfoChunk::append_byte(uint8_t b) {
-  _bytes.push_back(b);
-}
-
-void DyldInfoChunk::append_string(StringRef str) {
-  _bytes.insert(_bytes.end(), str.begin(), str.end());
-  _bytes.push_back('\0');
-}
-
-void DyldInfoChunk::append_uleb128(uint64_t value) {
-  uint8_t byte;
-  do {
-    byte = value & 0x7F;
-    value &= ~0x7F;
-    if ( value != 0 )
-      byte |= 0x80;
-    _bytes.push_back(byte);
-    value = value >> 7;
-  } while( byte >= 0x80 );
-}
-
-
-
-//===----------------------------------------------------------------------===//
-//  BindingInfoChunk
-//===----------------------------------------------------------------------===//
-
-BindingInfoChunk::BindingInfoChunk(MachOWriter &writer)
- : DyldInfoChunk(writer) {
-}
-
-const char* BindingInfoChunk::info() {
-  return "binding info";
-}
-
-void BindingInfoChunk::computeSize(const lld::File &file,
-                                    const std::vector<SectionChunk*> &chunks) {
-  for (const SectionChunk *chunk : chunks ) {
-    // skip lazy pointer section
-    if ( chunk->flags() == S_LAZY_SYMBOL_POINTERS )
-      continue;
-    // skip code sections
-    if ( chunk->flags() == (S_REGULAR | S_ATTR_PURE_INSTRUCTIONS) )
-      continue;
-    uint64_t segStartAddr = 0;
-    uint64_t segEndAddr = 0;
-    uint32_t segIndex = 0;
-    _writer.findSegment(chunk->segmentName(),
-                                    &segIndex, &segStartAddr, &segEndAddr);
-    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
-      const DefinedAtom* atom = info.atom;
-      StringRef targetName;
-      int ordinal;
-
-      // look for fixups pointing to shlib atoms
-      for (const Reference *ref : *atom ) {
-        const Atom *target = ref->target();
-        if ( target != nullptr ) {
-          const SharedLibraryAtom *shlTarget
-                                        = dyn_cast<SharedLibraryAtom>(target);
-          if ( shlTarget != nullptr ) {
-            assert(_writer.kindHandler().isPointer(ref->kind()));
-            targetName = shlTarget->name();
-            ordinal = 1; // FIXME
-          }
-        }
-      }
-
-      if ( targetName.empty() )
-        continue;
-
-      // write location of fixup
-      this->append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
-      uint64_t address = _writer.addressOfAtom(atom);
-      this->append_uleb128(address - segStartAddr);
-
-      // write ordinal
-      if ( ordinal <= 0 ) {
-        // special lookups are encoded as negative numbers in BindingInfo
-        this->append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
-                                          | (ordinal & BIND_IMMEDIATE_MASK) );
-      }
-      else if ( ordinal <= 15 ) {
-        // small ordinals are encoded in opcode
-        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
-      }
-      else {
-        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-        this->append_uleb128(ordinal);
-      }
-
-      // write binding type
-      this->append_byte(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER);
-
-      // write symbol name and flags
-      int flags = 0;
-      this->append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
-      this->append_string(targetName);
-
-      // write do bind
-      this->append_byte(BIND_OPCODE_DO_BIND);
-      this->append_byte(BIND_OPCODE_DONE);
-    }
-  }
-  _size = _bytes.size();
-}
-
-
-//===----------------------------------------------------------------------===//
-//  LazyBindingInfoChunk
-//===----------------------------------------------------------------------===//
-
-LazyBindingInfoChunk::LazyBindingInfoChunk(MachOWriter &writer)
- : DyldInfoChunk(writer) {
-}
-
-const char* LazyBindingInfoChunk::info() {
-  return "lazy binding info";
-}
-
-//
-// Called when lazy-binding-info is being laid out in __LINKEDIT.  We need
-// to find the helper atom which contains the instruction which loads an
-// immediate value that is the offset into the lazy-binding-info, and set
-// that immediate value to be the offset parameter.
-void LazyBindingInfoChunk::updateHelper(const DefinedAtom *lazyPointerAtom,
-                                        uint32_t offset) {
-  for (const Reference *ref : *lazyPointerAtom ) {
-    if ( ! _writer.kindHandler().isPointer(ref->kind() ) )
-      continue;
-    const Atom *targ = ref->target();
-    const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(targ);
-    assert(helperAtom != nullptr);
-    // Found helper atom.  Search it for Reference that is lazy immediate value.
-    for (const Reference *href : *helperAtom ) {
-      if ( _writer.kindHandler().isLazyImmediate(href->kind()) ) {
-        (const_cast<Reference*>(href))->setAddend(offset);
-        return;
-      }
-    }
-  }
-  assert(0 && "could not update helper lazy immediate value");
-}
-
-void LazyBindingInfoChunk::computeSize(const lld::File &file,
-                                    const std::vector<SectionChunk*> &chunks) {
-  for (const SectionChunk *chunk : chunks ) {
-    if ( chunk->flags() != S_LAZY_SYMBOL_POINTERS )
-      continue;
-    uint64_t segStartAddr = 0;
-    uint64_t segEndAddr = 0;
-    uint32_t segIndex = 0;
-    _writer.findSegment(chunk->segmentName(),
-                                    &segIndex, &segStartAddr, &segEndAddr);
-    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
-      const DefinedAtom *lazyPointerAtom = info.atom;
-      assert(lazyPointerAtom->contentType() == DefinedAtom::typeLazyPointer);
-      // Update help to have offset of the lazy binding info.
-      this->updateHelper(lazyPointerAtom, _bytes.size());
-
-      // Write location of fixup.
-      this->append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
-      uint64_t address = _writer.addressOfAtom(lazyPointerAtom);
-      this->append_uleb128(address - segStartAddr);
-
-      // write ordinal
-      int ordinal = 1;
-      if ( ordinal <= 0 ) {
-        // special lookups are encoded as negative numbers in BindingInfo
-        this->append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
-                                          | (ordinal & BIND_IMMEDIATE_MASK) );
-      }
-      else if ( ordinal <= 15 ) {
-        // small ordinals are encoded in opcode
-        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
-      }
-      else {
-        this->append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-        this->append_uleb128(ordinal);
-      }
-
-      // write symbol name and flags
-      int flags = 0;
-      StringRef name;
-      for (const Reference *ref : *lazyPointerAtom ) {
-        if ( _writer.kindHandler().isLazyTarget(ref->kind()) ) {
-          const Atom *shlib = ref->target();
-          assert(shlib != nullptr);
-          name = shlib->name();
-        }
-      }
-      assert(!name.empty());
-      this->append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
-      this->append_string(name);
-
-      // write do bind
-      this->append_byte(BIND_OPCODE_DO_BIND);
-      this->append_byte(BIND_OPCODE_DONE);
-    }
-  }
-  _size = _bytes.size();
-}
-
-
-//===----------------------------------------------------------------------===//
-//  SymbolTableChunk
-//===----------------------------------------------------------------------===//
-
-SymbolTableChunk::SymbolTableChunk(SymbolStringsChunk &str, MachOWriter &wrtr)
-  : _writer(wrtr), _stringsChunk(str) {
-}
-
-void SymbolTableChunk::write(uint8_t *chunkBuffer) {
-  const bool is64 = _writer.use64BitMachO();
-  const unsigned nlistSize = nlist::size(is64);
-  uint8_t *p = chunkBuffer;
-  for ( nlist &sym : _globalDefinedsymbols ) {
-    sym.copyTo(p, is64);
-    p += nlistSize;
-  }
-  for ( nlist &sym : _localDefinedsymbols ) {
-    sym.copyTo(p, is64);
-    p += nlistSize;
-  }
-  for ( nlist &sym : _undefinedsymbols ) {
-    sym.copyTo(p, is64);
-    p += nlistSize;
-  }
-}
-
-const char* SymbolTableChunk::info() {
-  return "symbol tables ";
-}
-
-uint32_t SymbolTableChunk::count() {
-  return _globalDefinedsymbols.size()
-       + _localDefinedsymbols.size()
-       + _undefinedsymbols.size();
-}
-
-uint8_t SymbolTableChunk::nType(const DefinedAtom *atom) {
-  uint8_t result = N_SECT;
-  switch ( atom->scope() ) {
-    case DefinedAtom::scopeTranslationUnit:
-      break;
-    case DefinedAtom::scopeLinkageUnit:
-      result |= N_EXT | N_PEXT;
-      break;
-    case DefinedAtom::scopeGlobal:
-      result |= N_EXT;
-      break;
-  }
-  return result;
-}
-
-void SymbolTableChunk::computeSize(const lld::File &file,
-                                   const std::vector<SectionChunk*> &chunks) {
-  // Add symbols for definitions
-  unsigned int sectionIndex = 1;
-  for (const SectionChunk *chunk : chunks ) {
-    for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
-      if ( info.atom->name().empty() )
-        continue;
-      uint64_t atomAddress = chunk->address() + info.offsetInSection;
-      nlist sym;
-      sym.n_strx = _stringsChunk.stringIndex(info.atom->name());
-      sym.n_type = this->nType(info.atom);
-      sym.n_sect = sectionIndex;
-      sym.n_desc = 0;
-      sym.n_value = atomAddress;
-      if ( info.atom->scope() == DefinedAtom::scopeGlobal )
-        _globalDefinedsymbols.push_back(sym);
-      else
-        _localDefinedsymbols.push_back(sym);
-    }
-    ++sectionIndex;
-  }
-
-  // Add symbols for undefined/sharedLibrary symbols
-  for (const SharedLibraryAtom* atom : file.sharedLibrary() ) {
-    nlist sym;
-    sym.n_strx = _stringsChunk.stringIndex(atom->name());
-    sym.n_type = N_UNDF;
-    sym.n_sect = 0;
-    sym.n_desc = 0;
-    sym.n_value = 0;
-    _undefinedsymbols.push_back(sym);
-  }
-
-  _size = nlist::size(_writer.use64BitMachO()) * this->count();
-}
-
-
-//===----------------------------------------------------------------------===//
-//  SymbolStringsChunk
-//===----------------------------------------------------------------------===//
-
-SymbolStringsChunk::SymbolStringsChunk() {
-  // mach-o reserves the first byte in the string pool so that
-  // zero is never a valid string index.
-  _strings.push_back('\0');
-}
-
-
-void SymbolStringsChunk::write(uint8_t *chunkBuffer) {
-  ::memcpy(chunkBuffer, &_strings[0], _strings.size());
-}
-
-const char* SymbolStringsChunk::info() {
-  return "symbol strings ";
-}
-
-void SymbolStringsChunk::computeSize(const lld::File &file,
-                                     const std::vector<SectionChunk*>&) {
-  _size = _strings.size();
-}
-
-
-uint32_t SymbolStringsChunk::stringIndex(StringRef str) {
-  uint32_t result = _strings.size();
-  _strings.insert(_strings.end(), str.begin(), str.end());
-  _strings.push_back('\0');
-  return result;
-}
-
-
-//===----------------------------------------------------------------------===//
-//  MachOWriter
-//===----------------------------------------------------------------------===//
-
-MachOWriter::MachOWriter(const MachOLinkingContext &context)
-    : _context(context), _referenceKindHandler(context.kindHandler()),
-      _cRuntimeFile(new CRuntimeFile(context)), _bindingInfo(nullptr),
-      _lazyBindingInfo(nullptr), _symbolTableChunk(nullptr),
-      _stringsChunk(nullptr), _entryAtom(nullptr), _linkEditStartOffset(0),
-      _linkEditStartAddress(0) {}
-
-void MachOWriter::build(const lld::File &file) {
-  // Create objects for each chunk.
-  this->createChunks(file);
-
-  // Now that SectionChunks have sizes, load commands can be laid out
-  _loadCommandsChunk->computeSize(file);
-
-  // Now that load commands are sized, padding can be computed
-  _paddingChunk->computeSize();
-
-  // Now that all chunks (except linkedit) have sizes, assign file offsets
-  this->assignFileOffsets();
-
-  // Now chunks have file offsets each atom can be assigned an address
-  this->buildAtomToAddressMap();
-
-  // Now that atoms have address, symbol table can be build
-  this->buildLinkEdit(file);
-
-  // Assign file offsets to linkedit chunks
-  this->assignLinkEditFileOffsets();
-
-  // Finally, update load commands to reflect linkEdit layout
-  _loadCommandsChunk->updateLoadCommandContent(file);
-}
-
-
-void MachOWriter::createChunks(const lld::File &file) {
-  // Assign atoms to chunks, creating new chunks as needed
-  std::map<DefinedAtom::ContentType, SectionChunk*> map;
-  for (const DefinedAtom* atom : file.defined() ) {
-    assert( atom->sectionChoice() == DefinedAtom::sectionBasedOnContent );
-    DefinedAtom::ContentType type = atom->contentType();
-    auto pos = map.find(type);
-    if ( pos == map.end() ) {
-      SectionChunk *chunk = SectionChunk::make(type, *this);
-      map[type] = chunk;
-      chunk->appendAtom(atom);
-    }
-    else {
-      pos->second->appendAtom(atom);
-    }
-  }
-
-  // Sort Chunks so ones in same segment are contiguous.
-
-
-  // Make chunks in __TEXT for mach_header and load commands at start.
-  MachHeaderChunk *mhc = new MachHeaderChunk(_context, file);
-  _chunks.push_back(mhc);
-
-  _loadCommandsChunk = new LoadCommandsChunk(*mhc, _context, *this);
-  _chunks.push_back(_loadCommandsChunk);
-
-  _paddingChunk = new LoadCommandPaddingChunk(*_loadCommandsChunk);
-  _chunks.push_back(_paddingChunk);
-
-  for (auto it=map.begin(); it != map.end(); ++it) {
-     _chunks.push_back(it->second);
-     _sectionChunks.push_back(it->second);
-     _loadCommandsChunk->addSection(it->second);
-  }
-
-  // Make LINKEDIT chunks.
-  _bindingInfo = new BindingInfoChunk(*this);
-  _lazyBindingInfo = new LazyBindingInfoChunk(*this);
-  _stringsChunk = new SymbolStringsChunk();
-  _symbolTableChunk = new SymbolTableChunk(*_stringsChunk, *this);
-  this->addLinkEditChunk(_bindingInfo);
-  this->addLinkEditChunk(_lazyBindingInfo);
-  this->addLinkEditChunk(_symbolTableChunk);
-  this->addLinkEditChunk(_stringsChunk);
-}
-
+  MachOWriter(const MachOLinkingContext &ctxt) : _context(ctxt) { }
 
-void MachOWriter::addLinkEditChunk(LinkEditChunk *chunk) {
-  _linkEditChunks.push_back(chunk);
-  _chunks.push_back(chunk);
-}
-
-
-void MachOWriter::buildAtomToAddressMap() {
-  DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
-                   << "assign atom addresses:\n");
-  const bool lookForEntry = _context.outputTypeHasEntry();
-  for (SectionChunk *chunk : _sectionChunks) {
-    for (const SectionChunk::AtomInfo &info : chunk->atoms()) {
-      _atomToAddress[info.atom] = chunk->address() + info.offsetInSection;
-      if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
-          (info.atom->size() != 0) &&
-          info.atom->name() == _context.entrySymbolName()) {
-        _entryAtom = info.atom;
-      }
-      DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
-              << "   address="
-              << llvm::format("0x%016X", _atomToAddress[info.atom])
-              << " atom=" << info.atom
-              << " name=" << info.atom->name() << "\n");
+  virtual error_code writeFile(const lld::File &file, StringRef path) {
+    // Construct empty normalized file from atoms.
+    ErrorOr<std::unique_ptr<NormalizedFile>> nFile = 
+                                normalized::normalizedFromAtoms(file, _context);
+    if (!nFile)
+      return nFile;
+    
+    // For debugging, write out yaml form of normalized file.
+    //writeYaml(*nFile->get(), llvm::errs());
+    
+    // Write normalized file as mach-o binary.
+    return writeBinary(*nFile->get(), path);
+  }
+  
+  virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &r) {
+    if (_context.outputFileType() == llvm::MachO::MH_EXECUTE) {
+      // When building main executables, add _main as required entry point.
+      r.emplace_back(new CRuntimeFile(_context));
     }
-  }
-}
-
-//void MachOWriter::dump() {
-//  for ( Chunk *chunk : _chunks ) {
-//    fprintf(stderr, "size=0x%08llX, fileOffset=0x%08llX, address=0x%08llX %s\n",
-//          chunk->size(), chunk->fileOffset(),chunk->address(), chunk->info());
-//  }
-//}
-
-void MachOWriter::assignFileOffsets() {
-  DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
-                    << "assign file offsets:\n");
-  uint64_t offset = 0;
-  uint64_t address = _context.pageZeroSize();
-  for (Chunk *chunk : _chunks) {
-    if (chunk->segmentName().equals("__LINKEDIT")) {
-      _linkEditStartOffset  = Chunk::alignTo(offset, 12);
-      _linkEditStartAddress = Chunk::alignTo(address, 12);
-      break;
-    }
-    chunk->assignFileOffset(offset, address);
-  }
-}
-
-void MachOWriter::assignLinkEditFileOffsets() {
-  DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
-                   << "assign LINKEDIT file offsets:\n");
-  uint64_t offset = _linkEditStartOffset;
-  uint64_t address = _linkEditStartAddress;
-  for ( Chunk *chunk : _linkEditChunks ) {
-    chunk->assignFileOffset(offset, address);
-  }
-}
-
-void MachOWriter::buildLinkEdit(const lld::File &file) {
-  for (LinkEditChunk *chunk : _linkEditChunks) {
-    chunk->computeSize(file, _sectionChunks);
-  }
-}
-
-
-uint64_t MachOWriter::addressOfAtom(const Atom *atom) {
-  return _atomToAddress[atom];
-}
-
-
-void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex,
-                                uint64_t *segStartAddr, uint64_t *segEndAddr) {
-  const uint64_t kInvalidAddress = (uint64_t)(-1);
-  StringRef lastSegName("__TEXT");
-  *segIndex = 0;
-  if (_context.pageZeroSize() != 0) {
-    *segIndex = 1;
-  }
-  *segStartAddr = kInvalidAddress;
-  *segEndAddr = kInvalidAddress;
-  for (SectionChunk *chunk : _sectionChunks ) {
-    if ( ! lastSegName.equals(chunk->segmentName()) ) {
-      *segIndex += 1;
-      lastSegName = chunk->segmentName();
-    }
-    if ( chunk->segmentName().equals(segmentName) ) {
-      uint64_t  chunkEndAddr = chunk->address() + chunk->size();
-      if ( *segStartAddr == kInvalidAddress ) {
-        *segStartAddr = chunk->address();
-        *segEndAddr = chunkEndAddr;
-      }
-      else if ( *segEndAddr < chunkEndAddr ) {
-        *segEndAddr = chunkEndAddr;
-      }
-    }
-  }
-}
-
-bool MachOWriter::use64BitMachO() const {
-  switch (_context.arch()) {
-  case MachOLinkingContext::arch_x86_64:
     return true;
-  case MachOLinkingContext::arch_x86:
-  case MachOLinkingContext::arch_armv6:
-  case MachOLinkingContext::arch_armv7:
-  case MachOLinkingContext::arch_armv7s:
-    return false;
-    default:
-      llvm_unreachable("Unknown mach-o arch");
   }
-}
-
-
-//
-// Creates a mach-o final linked image from the given atom graph and writes
-// it to the supplied output stream.
-//
-error_code MachOWriter::writeFile(const lld::File &file, StringRef path) {
-  this->build(file);
-
-// FIXME: re-enable when FileOutputBuffer is in LLVMSupport.a
-  uint64_t totalSize = _chunks.back()->fileOffset() + _chunks.back()->size();
-
-  OwningPtr<llvm::FileOutputBuffer> buffer;
-  error_code ec = llvm::FileOutputBuffer::create(path,
-                                          totalSize, buffer,
-                                          llvm::FileOutputBuffer::F_executable);
-  if ( ec )
-    return ec;
-
-  DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() << "writeFile:\n");
-  for ( Chunk *chunk : _chunks ) {
-    DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
-                      << "   fileOffset="
-                      << llvm::format("0x%08X", chunk->fileOffset())
-                      << " chunk="
-                      << chunk->info()
-                      << "\n");
-    chunk->write(buffer->getBufferStart()+chunk->fileOffset());
-  }
-  return buffer->commit();
-}
+private:
+   const MachOLinkingContext  &_context;
+ };
 
-bool
-MachOWriter::createImplicitFiles(std::vector<std::unique_ptr<File> > &result) {
-  result.push_back(std::move(_cRuntimeFile));
-  return true;
-}
 
 } // namespace mach_o
 

Modified: lld/trunk/test/darwin/hello-world.objtxt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/darwin/hello-world.objtxt?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/test/darwin/hello-world.objtxt (original)
+++ lld/trunk/test/darwin/hello-world.objtxt Wed Nov  6 15:36:55 2013
@@ -32,5 +32,5 @@ shared-library-atoms:
 ...
 
 # CHECK:	{{[0-9a-f]+}} T _main
-# CHECK:	00000000 u _printf
-# CHECK:	00000000 u dyld_stub_binder
+# CHECK:	00000000 U _printf
+# CHECK:	00000000 U dyld_stub_binder

Modified: lld/trunk/unittests/MachOTests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/MachOTests/CMakeLists.txt?rev=194167&r1=194166&r2=194167&view=diff
==============================================================================
--- lld/trunk/unittests/MachOTests/CMakeLists.txt (original)
+++ lld/trunk/unittests/MachOTests/CMakeLists.txt Wed Nov  6 15:36:55 2013
@@ -1,5 +1,7 @@
 
 add_lld_unittest(lldMachOTests
+  MachONormalizedFileBinaryReaderTests.cpp
+  MachONormalizedFileBinaryWriterTests.cpp
   MachONormalizedFileYAMLTests.cpp
   )
 

Added: lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp?rev=194167&view=auto
==============================================================================
--- lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp (added)
+++ lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp Wed Nov  6 15:36:55 2013
@@ -0,0 +1,714 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryReaderTests.cpp ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include <llvm/Support/MachO.h>
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+
+#include <assert.h>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::ErrorOr;
+
+using namespace lld::mach_o::normalized;
+using namespace llvm::MachO;
+
+static std::unique_ptr<NormalizedFile> 
+fromBinary(const uint8_t bytes[], unsigned length) {
+
+  StringRef sr((const char*)bytes, length);
+  std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(sr, "", false));
+  ErrorOr<std::unique_ptr<NormalizedFile>> r 
+                                    = lld::mach_o::normalized::readBinary(mb);
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+
+TEST(BinaryReaderTest, empty_obj_x86_64) {
+  const uint8_t fileBytes[] = {
+      0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 
+      0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 
+      0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x19, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+      0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(BinaryReaderTest, empty_obj_x86) {
+  const uint8_t fileBytes[] = {
+      0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00,
+      0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(BinaryReaderTest, empty_obj_ppc) {
+  const uint8_t fileBytes[] = {
+      0xfe, 0xed, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x12,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c,
+      0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+      0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(BinaryReaderTest, empty_obj_armv7) {
+  const uint8_t fileBytes[] = {
+      0xce, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x00,
+      0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
+      0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+      0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65,
+      0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45,
+      0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+
+TEST(BinaryReaderTest, hello_obj_x86_64) {
+  const uint8_t fileBytes[] = {
+    0xCF, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x01,
+    0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x19, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x70, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0xA4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x9D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0xB4, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+    0xE4, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+    0x0B, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10,
+    0x48, 0x8D, 0x3D, 0x00, 0x00, 0x00, 0x00, 0xC7,
+    0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00,
+    0xE8, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00,
+    0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x48,
+    0x83, 0xC4, 0x10, 0x5D, 0xC3, 0x68, 0x65, 0x6C,
+    0x6C, 0x6F, 0x0A, 0x00, 0x19, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x2D, 0x0B, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x1D, 0x0F, 0x00, 0x00, 0x00,
+    0x0E, 0x02, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+    0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+    0x74, 0x66, 0x00, 0x4C, 0x5F, 0x2E, 0x73, 0x74,
+    0x72, 0x00, 0x00, 0x00 };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+    
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 4U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(text.content.size(), 45UL);
+  EXPECT_EQ((int)(text.content[0]), 0x55);
+  EXPECT_EQ((int)(text.content[1]), 0x48);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 2UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x19));
+  EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 2U);
+  const Relocation& str = text.relocations[1];
+  EXPECT_EQ(str.offset, Hex32(0xB));
+  EXPECT_EQ(str.type, X86_64_RELOC_SIGNED);
+  EXPECT_EQ(str.length, 2);
+  EXPECT_EQ(str.isExtern, true);
+  EXPECT_EQ(str.symbol, 0U);
+  
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ(cstring.alignment, 0U);
+  EXPECT_EQ(cstring.address, 0x02DULL);
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 1UL);
+  const Symbol& strLabel = f->localSymbols[0];
+  EXPECT_EQ(strLabel.type, N_SECT);
+  EXPECT_EQ(strLabel.sect, 2);
+  EXPECT_EQ(strLabel.value, Hex64(0x2D));
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+
+TEST(BinaryReaderTest, hello_obj_x86) {
+  const uint8_t fileBytes[] = {
+    0xCE, 0xFA, 0xED, 0xFE, 0x07, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x37, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0x7C, 0x01, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x55, 0x89, 0xE5, 0x83,
+    0xEC, 0x18, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x58,
+    0x8D, 0x80, 0x25, 0x00, 0x00, 0x00, 0xC7, 0x45,
+    0xFC, 0x00, 0x00, 0x00, 0x00, 0x89, 0x04, 0x24,
+    0xE8, 0xDF, 0xFF, 0xFF, 0xFF, 0xB9, 0x00, 0x00,
+    0x00, 0x00, 0x89, 0x45, 0xF8, 0x89, 0xC8, 0x83,
+    0xC4, 0x18, 0x5D, 0xC3, 0x68, 0x65, 0x6C, 0x6C,
+    0x6F, 0x0A, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x0D, 0x0E, 0x00, 0x00, 0xA4,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1,
+    0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x6D, 0x61,
+    0x69, 0x6E, 0x00, 0x5F, 0x70, 0x72, 0x69, 0x6E,
+    0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+    
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 4U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(text.content.size(), 48UL);
+  EXPECT_EQ((int)(text.content[0]), 0x55);
+  EXPECT_EQ((int)(text.content[1]), 0x89);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 3UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1D));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(call.pcRel, true);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& sectDiff = text.relocations[1];
+  EXPECT_EQ(sectDiff.offset, Hex32(0xE));
+  EXPECT_EQ(sectDiff.scattered, true);
+  EXPECT_EQ(sectDiff.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(sectDiff.pcRel, false);
+  EXPECT_EQ(sectDiff.length, 2);
+  EXPECT_EQ(sectDiff.value, 0x30U);
+  const Relocation& pair = text.relocations[2];
+  EXPECT_EQ(pair.offset, Hex32(0x0));
+  EXPECT_EQ(pair.scattered, true);
+  EXPECT_EQ(pair.type, GENERIC_RELOC_PAIR);
+  EXPECT_EQ(pair.pcRel, false);
+  EXPECT_EQ(pair.length, 2);
+  EXPECT_EQ(pair.value, 0x0BU);
+  
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ(cstring.alignment, 0U);
+  EXPECT_EQ(cstring.address, 0x030ULL);
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+
+TEST(BinaryReaderTest, hello_obj_armv7) {
+  const uint8_t fileBytes[] = {
+    0xCE, 0xFA, 0xED, 0xFE, 0x0C, 0x00, 0x00, 0x00,
+    0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x31, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2A, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x2A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x6E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00,
+    0x10, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
+    0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0xB5, 0x6F, 0x46,
+    0x82, 0xB0, 0x40, 0xF2, 0x18, 0x00, 0xC0, 0xF2,
+    0x00, 0x00, 0x78, 0x44, 0x00, 0x21, 0xC0, 0xF2,
+    0x00, 0x01, 0x01, 0x91, 0xFF, 0xF7, 0xF2, 0xFF,
+    0x00, 0x21, 0xC0, 0xF2, 0x00, 0x01, 0x00, 0x90,
+    0x08, 0x46, 0x02, 0xB0, 0x80, 0xBD, 0x68, 0x65,
+    0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x6D,
+    0x0A, 0x00, 0x00, 0xB9, 0x2A, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0xB1, 0x0E, 0x00, 0x00, 0x00,
+    0x06, 0x00, 0x00, 0xA9, 0x2A, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xA1, 0x0E, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x0F, 0x01, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+    0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+    
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 2U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(text.content.size(), 42UL);
+  EXPECT_EQ((int)(text.content[0]), 0x80);
+  EXPECT_EQ((int)(text.content[1]), 0xB5);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 5UL);
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x18));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& movt = text.relocations[1];
+  EXPECT_EQ(movt.offset, Hex32(0xA));
+  EXPECT_EQ(movt.scattered, true);
+  EXPECT_EQ(movt.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movt.length, 3);
+  EXPECT_EQ(movt.value, Hex32(0x2A));
+  const Relocation& movtPair = text.relocations[2];
+  EXPECT_EQ(movtPair.offset, Hex32(0x18));
+  EXPECT_EQ(movtPair.scattered, true);
+  EXPECT_EQ(movtPair.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movtPair.length, 3);
+  EXPECT_EQ(movtPair.value, Hex32(0xE));
+  const Relocation& movw = text.relocations[3];
+  EXPECT_EQ(movw.offset, Hex32(0x6));
+  EXPECT_EQ(movw.scattered, true);
+  EXPECT_EQ(movw.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movw.length, 2);
+  EXPECT_EQ(movw.value, Hex32(0x2A));
+  const Relocation& movwPair = text.relocations[4];
+  EXPECT_EQ(movwPair.offset, Hex32(0x0));
+  EXPECT_EQ(movwPair.scattered, true);
+  EXPECT_EQ(movwPair.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movwPair.length, 2);
+  EXPECT_EQ(movwPair.value, Hex32(0xE));
+  
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ(cstring.alignment, 0U);
+  EXPECT_EQ(cstring.address, 0x02AULL);
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+}
+
+
+TEST(BinaryReaderTest, hello_obj_ppc) {
+  const uint8_t fileBytes[] = {
+    0xFE, 0xED, 0xFA, 0xCE, 0x00, 0x00, 0x00, 0x12,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x28,
+    0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x01, 0x44,
+    0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x74, 0x65,
+    0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x5F, 0x5F, 0x54, 0x45,
+    0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x01, 0x44,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x90,
+    0x00, 0x00, 0x00, 0x05, 0x80, 0x00, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6E,
+    0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x5F, 0x5F, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x07,
+    0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0xB8,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0xD0,
+    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0B,
+    0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x02, 0xA6,
+    0xBF, 0xC1, 0xFF, 0xF8, 0x90, 0x01, 0x00, 0x08,
+    0x94, 0x21, 0xFF, 0xB0, 0x7C, 0x3E, 0x0B, 0x78,
+    0x42, 0x9F, 0x00, 0x05, 0x7F, 0xE8, 0x02, 0xA6,
+    0x3C, 0x5F, 0x00, 0x00, 0x38, 0x62, 0x00, 0x2C,
+    0x4B, 0xFF, 0xFF, 0xDD, 0x38, 0x00, 0x00, 0x00,
+    0x7C, 0x03, 0x03, 0x78, 0x80, 0x21, 0x00, 0x00,
+    0x80, 0x01, 0x00, 0x08, 0x7C, 0x08, 0x03, 0xA6,
+    0xBB, 0xC1, 0xFF, 0xF8, 0x4E, 0x80, 0x00, 0x20,
+    0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0xD3,
+    0xAB, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x44,
+    0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+    0xAC, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x44,
+    0xA1, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x18,
+    0x00, 0x00, 0x00, 0x01, 0x0F, 0x01, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x5F, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x5F,
+    0x70, 0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x00
+  };
+  std::unique_ptr<NormalizedFile> f = fromBinary(fileBytes, sizeof(fileBytes));
+  
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ((int)(f->fileType), MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  const Section& text = f->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(text.type, S_REGULAR);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 2U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(text.content.size(), 68UL);
+  EXPECT_EQ((int)(text.content[0]), 0x7C);
+  EXPECT_EQ((int)(text.content[1]), 0x08);
+  EXPECT_TRUE(text.indirectSymbols.empty());
+  EXPECT_EQ(text.relocations.size(), 5UL);
+  const Relocation& bl = text.relocations[0];
+  EXPECT_EQ(bl.offset, Hex32(0x24));
+  EXPECT_EQ(bl.type, PPC_RELOC_BR24);
+  EXPECT_EQ(bl.length, 2);
+  EXPECT_EQ(bl.isExtern, true);
+  EXPECT_EQ(bl.symbol, 1U);
+  const Relocation& lo = text.relocations[1];
+  EXPECT_EQ(lo.offset, Hex32(0x20));
+  EXPECT_EQ(lo.scattered, true);
+  EXPECT_EQ(lo.type, PPC_RELOC_LO16_SECTDIFF);
+  EXPECT_EQ(lo.length, 2);
+  EXPECT_EQ(lo.value, Hex32(0x44));
+  const Relocation& loPair = text.relocations[2];
+  EXPECT_EQ(loPair.offset, Hex32(0x0));
+  EXPECT_EQ(loPair.scattered, true);
+  EXPECT_EQ(loPair.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(loPair.length, 2);
+  EXPECT_EQ(loPair.value, Hex32(0x18));
+  const Relocation& ha = text.relocations[3];
+  EXPECT_EQ(ha.offset, Hex32(0x1C));
+  EXPECT_EQ(ha.scattered, true);
+  EXPECT_EQ(ha.type, PPC_RELOC_HA16_SECTDIFF);
+  EXPECT_EQ(ha.length, 2);
+  EXPECT_EQ(ha.value, Hex32(0x44));
+  const Relocation& haPair = text.relocations[4];
+  EXPECT_EQ(haPair.offset, Hex32(0x2c));
+  EXPECT_EQ(haPair.scattered, true);
+  EXPECT_EQ(haPair.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(haPair.length, 2);
+  EXPECT_EQ(haPair.value, Hex32(0x18));
+  
+  const Section& cstring = f->sections[1];
+  EXPECT_TRUE(cstring.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(cstring.sectionName.equals("__cstring"));
+  EXPECT_EQ(cstring.type, S_CSTRING_LITERALS);
+  EXPECT_EQ(cstring.attributes, SectionAttr(0));
+  EXPECT_EQ(cstring.alignment, 2U);
+  EXPECT_EQ(cstring.address, 0x044ULL);
+  EXPECT_EQ(cstring.content.size(), 7UL);
+  EXPECT_EQ((int)(cstring.content[0]), 0x68);
+  EXPECT_EQ((int)(cstring.content[1]), 0x65);
+  EXPECT_EQ((int)(cstring.content[2]), 0x6c);
+  EXPECT_TRUE(cstring.indirectSymbols.empty());
+  EXPECT_TRUE(cstring.relocations.empty());
+  
+  EXPECT_EQ(f->localSymbols.size(), 0UL);
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& mainLabel = f->globalSymbols[0];
+  EXPECT_TRUE(mainLabel.name.equals("_main"));
+  EXPECT_EQ(mainLabel.type, N_SECT);
+  EXPECT_EQ(mainLabel.sect, 1);
+  EXPECT_EQ(mainLabel.scope, SymbolScope(N_EXT));
+  EXPECT_EQ(mainLabel.value, Hex64(0x0));
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& printfLabel = f->undefinedSymbols[0];
+  EXPECT_TRUE(printfLabel.name.equals("_printf"));
+  EXPECT_EQ(printfLabel.type, N_UNDF);
+  EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT));
+  
+  writeBinary(*f, "/tmp/foo.o");
+
+}
+

Added: lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp?rev=194167&view=auto
==============================================================================
--- lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp (added)
+++ lld/trunk/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp Wed Nov  6 15:36:55 2013
@@ -0,0 +1,685 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileBinaryWriterTests.cpp ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/Twine.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/MachO.h>
+#include <llvm/Support/system_error.h>
+#include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h"
+
+#include <assert.h>
+#include <vector>
+
+using llvm::StringRef;
+using llvm::MemoryBuffer;
+using llvm::OwningPtr;
+using llvm::SmallString;
+using llvm::Twine;
+using llvm::ErrorOr;
+using llvm::error_code;
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+
+static std::unique_ptr<NormalizedFile> 
+fromBinary(StringRef path) {
+
+  OwningPtr<MemoryBuffer> result;
+  error_code ec = MemoryBuffer::getFile(path, result);
+  EXPECT_FALSE(ec);
+  
+
+  
+  std::unique_ptr<MemoryBuffer> mb(result.take());
+  ErrorOr<std::unique_ptr<NormalizedFile>> r 
+                                    = lld::mach_o::normalized::readBinary(mb);
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+
+static Relocation 
+makeReloc(unsigned addr, bool rel, bool ext, RelocationInfoType type, 
+                                                              unsigned sym) {
+  Relocation result;
+  result.offset = addr;
+  result.scattered = false;
+  result.type = type;
+  result.length = 2;
+  result.pcRel = rel;
+  result.isExtern = ext;
+  result.value = 0;
+  result.symbol = sym;
+  return result;
+}
+
+static Relocation 
+makeScatReloc(unsigned addr, RelocationInfoType type, unsigned value) {
+  Relocation result;
+  result.offset = addr;
+  result.scattered = true;
+  result.type = type;
+  result.length = 2;
+  result.pcRel = false;
+  result.isExtern = true;
+  result.value = value;
+  result.symbol = 0;
+  return result;
+}
+
+static Symbol 
+makeUndefSymbol(StringRef name) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_UNDF;
+  sym.scope = N_EXT;
+  sym.sect = NO_SECT;
+  sym.desc = 0;
+  sym.value = 0;
+  return sym;
+}
+
+
+static Symbol 
+makeSymbol(StringRef name, unsigned addr) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_SECT;
+  sym.scope = N_EXT;
+  sym.sect = 1;
+  sym.desc = 0;
+  sym.value = addr;
+  return sym;
+}
+
+static Symbol 
+makeThumbSymbol(StringRef name, unsigned addr) {
+  Symbol sym;
+  sym.name = name;
+  sym.type = N_SECT;
+  sym.scope = N_EXT;
+  sym.sect = 1;
+  sym.desc = N_ARM_THUMB_DEF;
+  sym.value = addr;
+  return sym;
+}
+
+TEST(BinaryWriterTest, obj_relocs_x86_64) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86_64;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 4;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0xe8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x05, 
+      0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x00, 0x00, 
+      0x00, 0x00, 0x8b, 0x05, 0x00, 0x00, 0x00, 0x00, 
+      0xc6, 0x05, 0xff, 0xff, 0xff, 0xff, 0x12, 0xc7, 
+      0x05, 0xfc, 0xff, 0xff, 0xff, 0x78, 0x56, 0x34, 
+      0x12, 0x48, 0x8b, 0x3d, 0x00, 0x00, 0x00, 0x00 };
+
+    text.content.assign(textBytes, textBytes+sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x01, false, true, X86_64_RELOC_BRANCH, 1));
+    text.relocations.push_back(makeReloc(0x08, false, true, X86_64_RELOC_GOT_LOAD, 1));
+    text.relocations.push_back(makeReloc(0x0E, false, true, X86_64_RELOC_GOT, 1));
+    text.relocations.push_back(makeReloc(0x14, false, true, X86_64_RELOC_SIGNED, 1));
+    text.relocations.push_back(makeReloc(0x1A, false, true, X86_64_RELOC_SIGNED_1, 1));
+    text.relocations.push_back(makeReloc(0x21, false, true, X86_64_RELOC_SIGNED_4, 1));
+    text.relocations.push_back(makeReloc(0x2C, false, true, X86_64_RELOC_TLV, 2));
+ 
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+  
+    error_code ec = llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    ec = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec);
+  }
+  std::unique_ptr<NormalizedFile> f2 = fromBinary(tmpFl);
+  EXPECT_EQ(lld::MachOLinkingContext::arch_x86_64, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+  
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  const Symbol& tbarUndef = f2->undefinedSymbols[1];
+  EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+  EXPECT_EQ(N_UNDF, tbarUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+  
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 4U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(48UL, text.content.size());
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1));
+  EXPECT_EQ(call.type, X86_64_RELOC_BRANCH);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 1U);
+  const Relocation& gotLoad = text.relocations[1];
+  EXPECT_EQ(gotLoad.offset, Hex32(0x8));
+  EXPECT_EQ(gotLoad.type, X86_64_RELOC_GOT_LOAD);
+  EXPECT_EQ(gotLoad.length, 2);
+  EXPECT_EQ(gotLoad.isExtern, true);
+  EXPECT_EQ(gotLoad.symbol, 1U);
+  const Relocation& gotUse = text.relocations[2];
+  EXPECT_EQ(gotUse.offset, Hex32(0xE));
+  EXPECT_EQ(gotUse.type, X86_64_RELOC_GOT);
+  EXPECT_EQ(gotUse.length, 2);
+  EXPECT_EQ(gotUse.isExtern, true);
+  EXPECT_EQ(gotUse.symbol, 1U);
+  const Relocation& signed0 = text.relocations[3];
+  EXPECT_EQ(signed0.offset, Hex32(0x14));
+  EXPECT_EQ(signed0.type, X86_64_RELOC_SIGNED);
+  EXPECT_EQ(signed0.length, 2);
+  EXPECT_EQ(signed0.isExtern, true);
+  EXPECT_EQ(signed0.symbol, 1U);
+  const Relocation& signed1 = text.relocations[4];
+  EXPECT_EQ(signed1.offset, Hex32(0x1A));
+  EXPECT_EQ(signed1.type, X86_64_RELOC_SIGNED_1);
+  EXPECT_EQ(signed1.length, 2);
+  EXPECT_EQ(signed1.isExtern, true);
+  EXPECT_EQ(signed1.symbol, 1U);
+  const Relocation& signed4 = text.relocations[5];
+  EXPECT_EQ(signed4.offset, Hex32(0x21));
+  EXPECT_EQ(signed4.type, X86_64_RELOC_SIGNED_4);
+  EXPECT_EQ(signed4.length, 2);
+  EXPECT_EQ(signed4.isExtern, true);
+  EXPECT_EQ(signed4.symbol, 1U);
+  
+  error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_x86) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 4;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+       0xe8, 0xfb, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00,
+       0x00, 0x00, 0x8b, 0xb0, 0xfb, 0xff, 0xff, 0xff,
+       0x8b, 0x80, 0x11, 0x00, 0x00, 0x00 };
+
+    text.content.assign(textBytes, textBytes+sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x01, true, true, GENERIC_RELOC_VANILLA, 0));
+    text.relocations.push_back(makeReloc(0x06, false, true, GENERIC_RELOC_VANILLA, 0));
+    text.relocations.push_back(makeScatReloc(0x0c, GENERIC_RELOC_LOCAL_SECTDIFF, 0));
+    text.relocations.push_back(makeScatReloc(0x0, GENERIC_RELOC_PAIR, 5));
+    text.relocations.push_back(makeReloc(0x12, true, true, GENERIC_RELOC_TLV, 1));
+ 
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_tbar"));
+ 
+    error_code ec = llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    ec = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec);
+  }
+  std::unique_ptr<NormalizedFile> f2 = fromBinary(tmpFl);
+  EXPECT_EQ(lld::MachOLinkingContext::arch_x86, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+  
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_TRUE(f2->globalSymbols.empty());
+  EXPECT_EQ(2UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  const Symbol& tbarUndef = f2->undefinedSymbols[1];
+  EXPECT_TRUE(tbarUndef.name.equals("_tbar"));
+  EXPECT_EQ(N_UNDF, tbarUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), tbarUndef.scope);
+  
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 4U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(22UL, text.content.size());
+  const Relocation& call = text.relocations[0];
+  EXPECT_EQ(call.offset, Hex32(0x1));
+  EXPECT_EQ(call.scattered, false);
+  EXPECT_EQ(call.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(call.pcRel, true);
+  EXPECT_EQ(call.length, 2);
+  EXPECT_EQ(call.isExtern, true);
+  EXPECT_EQ(call.symbol, 0U);
+  const Relocation& absLoad = text.relocations[1];
+  EXPECT_EQ(absLoad.offset, Hex32(0x6));
+  EXPECT_EQ(absLoad.scattered, false);
+  EXPECT_EQ(absLoad.type, GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(absLoad.pcRel, false);
+  EXPECT_EQ(absLoad.length, 2);
+  EXPECT_EQ(absLoad.isExtern, true);
+  EXPECT_EQ(absLoad.symbol,0U);
+  const Relocation& pic1 = text.relocations[2];
+  EXPECT_EQ(pic1.offset, Hex32(0xc));
+  EXPECT_EQ(pic1.scattered, true);
+  EXPECT_EQ(pic1.type, GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(pic1.length, 2);
+  EXPECT_EQ(pic1.value, 0U);
+  const Relocation& pic2 = text.relocations[3];
+  EXPECT_EQ(pic2.offset, Hex32(0x0));
+  EXPECT_EQ(pic1.scattered, true);
+  EXPECT_EQ(pic2.type, GENERIC_RELOC_PAIR);
+  EXPECT_EQ(pic2.length, 2);
+  EXPECT_EQ(pic2.value, 5U);
+  const Relocation& tlv = text.relocations[4];
+  EXPECT_EQ(tlv.offset, Hex32(0x12));
+  EXPECT_EQ(tlv.type, GENERIC_RELOC_TLV);
+  EXPECT_EQ(tlv.length, 2);
+  EXPECT_EQ(tlv.isExtern, true);
+  EXPECT_EQ(tlv.symbol, 1U);
+  
+  //llvm::errs() << "temp = " << tmpFl << "\n";
+  error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_armv7) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_armv7;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 2;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0xff, 0xf7, 0xfe, 0xef, 0x40, 0xf2, 0x05, 0x01, 
+      0xc0, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0xbf };
+
+    text.content.assign(textBytes, textBytes+sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x00, true, true, 
+                                        ARM_THUMB_RELOC_BR22, 2));
+    text.relocations.push_back(makeScatReloc(0x04, 
+                                        ARM_RELOC_HALF_SECTDIFF, 0x10));
+    text.relocations.push_back(makeScatReloc(0x00, 
+                                        ARM_RELOC_PAIR, 0xC));
+    text.relocations.push_back(makeScatReloc(0x08, 
+                                        ARM_RELOC_HALF_SECTDIFF, 0x10));
+    text.relocations.push_back(makeScatReloc(0x00, 
+                                        ARM_RELOC_PAIR, 0xC));
+    text.relocations.push_back(makeReloc(0x0C, false, true, 
+                                        ARM_RELOC_VANILLA, 2));
+ 
+    f.globalSymbols.push_back(makeThumbSymbol("_foo", 0x00));
+    f.globalSymbols.push_back(makeThumbSymbol("_foo2", 0x10));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+    error_code ec = llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    ec = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec);
+  }
+  std::unique_ptr<NormalizedFile> f2 = fromBinary(tmpFl);
+  EXPECT_EQ(lld::MachOLinkingContext::arch_armv7, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+  
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_EQ(2UL, f2->globalSymbols.size());
+  const Symbol& fooDef = f2->globalSymbols[0];
+  EXPECT_TRUE(fooDef.name.equals("_foo"));
+  EXPECT_EQ(N_SECT, fooDef.type);
+  EXPECT_EQ(1, fooDef.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+  const Symbol& foo2Def = f2->globalSymbols[1];
+  EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+  EXPECT_EQ(N_SECT, foo2Def.type);
+  EXPECT_EQ(1, foo2Def.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+  
+  EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 2U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(18UL, text.content.size());
+  const Relocation& blx = text.relocations[0];
+  EXPECT_EQ(blx.offset, Hex32(0x0));
+  EXPECT_EQ(blx.scattered, false);
+  EXPECT_EQ(blx.type, ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(blx.pcRel, true);
+  EXPECT_EQ(blx.length, 2);
+  EXPECT_EQ(blx.isExtern, true);
+  EXPECT_EQ(blx.symbol, 2U);
+  const Relocation& movw1 = text.relocations[1];
+  EXPECT_EQ(movw1.offset, Hex32(0x4));
+  EXPECT_EQ(movw1.scattered, true);
+  EXPECT_EQ(movw1.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movw1.length, 2);
+  EXPECT_EQ(movw1.value, 0x10U);
+  const Relocation& movw2 = text.relocations[2];
+  EXPECT_EQ(movw2.offset, Hex32(0x0));
+  EXPECT_EQ(movw2.scattered, true);
+  EXPECT_EQ(movw2.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movw2.length, 2);
+  EXPECT_EQ(movw2.value, Hex32(0xC));
+   const Relocation& movt1 = text.relocations[3];
+  EXPECT_EQ(movt1.offset, Hex32(0x8));
+  EXPECT_EQ(movt1.scattered, true);
+  EXPECT_EQ(movt1.type, ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(movt1.length, 2);
+  EXPECT_EQ(movt1.value, Hex32(0x10));
+  const Relocation& movt2 = text.relocations[4];
+  EXPECT_EQ(movt2.offset, Hex32(0x0));
+  EXPECT_EQ(movt2.scattered, true);
+  EXPECT_EQ(movt2.type, ARM_RELOC_PAIR);
+  EXPECT_EQ(movt2.length, 2);
+  EXPECT_EQ(movt2.value, Hex32(0xC));
+ const Relocation& absPointer = text.relocations[5];
+  EXPECT_EQ(absPointer.offset, Hex32(0xC));
+  EXPECT_EQ(absPointer.type, ARM_RELOC_VANILLA);
+  EXPECT_EQ(absPointer.length, 2);
+  EXPECT_EQ(absPointer.isExtern, true);
+  EXPECT_EQ(absPointer.symbol, 2U);
+  
+  //llvm::errs() << "temp = " << tmpFl << "\n";
+  error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+TEST(BinaryWriterTest, obj_relocs_ppc) {
+  SmallString<128> tmpFl;
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_ppc;
+    f.fileType = MH_OBJECT;
+    f.flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    f.sections.resize(1);
+    Section& text = f.sections.front();
+    text.segmentName = "__TEXT";
+    text.sectionName = "__text";
+    text.type = S_REGULAR;
+    text.attributes = SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS);
+    text.alignment = 2;
+    text.address = 0;
+    const uint8_t textBytes[] = {
+      0x48, 0x00, 0x00, 0x01, 0x40, 0x82, 0xff, 0xfc,
+      0x3c, 0x62, 0x00, 0x00, 0x3c, 0x62, 0x00, 0x00,
+      0x80, 0x63, 0x00, 0x24, 0x80, 0x63, 0x00, 0x24,
+      0x3c, 0x40, 0x00, 0x00, 0x3c, 0x60, 0x00, 0x00,
+      0x80, 0x42, 0x00, 0x28, 0x80, 0x63, 0x00, 0x28,
+      0x60, 0x00, 0x00, 0x00 };
+
+    text.content.assign(textBytes, textBytes+sizeof(textBytes));
+    text.relocations.push_back(makeReloc(0x00, true, true, 
+                                        PPC_RELOC_BR24, 2));
+    text.relocations.push_back(makeReloc(0x04, true, true, 
+                                        PPC_RELOC_BR14, 2));
+    text.relocations.push_back(makeScatReloc(0x08, 
+                                        PPC_RELOC_HI16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x24, 
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x0C, 
+                                        PPC_RELOC_HA16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x24, 
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x10, 
+                                        PPC_RELOC_LO16_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x00, 
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeScatReloc(0x14, 
+                                        PPC_RELOC_LO14_SECTDIFF, 0x28));
+    text.relocations.push_back(makeScatReloc(0x00, 
+                                        PPC_RELOC_PAIR, 0x4));
+    text.relocations.push_back(makeReloc(0x18, false, false,
+                                        PPC_RELOC_HI16, 1));
+    text.relocations.push_back(makeReloc(0x28, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x1C, false, false,
+                                        PPC_RELOC_HA16, 1));
+    text.relocations.push_back(makeReloc(0x28, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x20, false, false,
+                                        PPC_RELOC_LO16, 1));
+    text.relocations.push_back(makeReloc(0x00, false, false,
+                                        PPC_RELOC_PAIR, 0));
+    text.relocations.push_back(makeReloc(0x24, false, false,
+                                        PPC_RELOC_LO14, 1));
+    text.relocations.push_back(makeReloc(0x00, false, false,
+                                        PPC_RELOC_PAIR, 0));
+
+    f.globalSymbols.push_back(makeSymbol("_foo", 0x00));
+    f.globalSymbols.push_back(makeSymbol("_foo2", 0x28));
+    f.undefinedSymbols.push_back(makeUndefSymbol("_bar"));
+
+    error_code ec = llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl);
+    EXPECT_FALSE(ec);
+    ec = writeBinary(f, tmpFl);
+    EXPECT_FALSE(ec);
+  }
+  std::unique_ptr<NormalizedFile> f2 = fromBinary(tmpFl);
+  EXPECT_EQ(lld::MachOLinkingContext::arch_ppc, f2->arch);
+  EXPECT_EQ(MH_OBJECT, f2->fileType);
+  EXPECT_EQ(FileFlags(MH_SUBSECTIONS_VIA_SYMBOLS), f2->flags);
+  
+  EXPECT_TRUE(f2->localSymbols.empty());
+  EXPECT_EQ(2UL, f2->globalSymbols.size());
+  const Symbol& fooDef = f2->globalSymbols[0];
+  EXPECT_TRUE(fooDef.name.equals("_foo"));
+  EXPECT_EQ(N_SECT, fooDef.type);
+  EXPECT_EQ(1, fooDef.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), fooDef.scope);
+  const Symbol& foo2Def = f2->globalSymbols[1];
+  EXPECT_TRUE(foo2Def.name.equals("_foo2"));
+  EXPECT_EQ(N_SECT, foo2Def.type);
+  EXPECT_EQ(1, foo2Def.sect);
+  EXPECT_EQ(SymbolScope(N_EXT), foo2Def.scope);
+  
+  EXPECT_EQ(1UL, f2->undefinedSymbols.size());
+  const Symbol& barUndef = f2->undefinedSymbols[0];
+  EXPECT_TRUE(barUndef.name.equals("_bar"));
+  EXPECT_EQ(N_UNDF, barUndef.type);
+  EXPECT_EQ(SymbolScope(N_EXT), barUndef.scope);
+  
+  EXPECT_EQ(1UL, f2->sections.size());
+  const Section& text = f2->sections[0];
+  EXPECT_TRUE(text.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(text.sectionName.equals("__text"));
+  EXPECT_EQ(S_REGULAR, text.type);
+  EXPECT_EQ(text.attributes,SectionAttr(S_ATTR_PURE_INSTRUCTIONS 
+                                      | S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(text.alignment, 2U);
+  EXPECT_EQ(text.address, 0x0ULL);
+  EXPECT_EQ(44UL, text.content.size());
+  const Relocation& br24 = text.relocations[0];
+  EXPECT_EQ(br24.offset, Hex32(0x0));
+  EXPECT_EQ(br24.scattered, false);
+  EXPECT_EQ(br24.type, PPC_RELOC_BR24);
+  EXPECT_EQ(br24.pcRel, true);
+  EXPECT_EQ(br24.length, 2);
+  EXPECT_EQ(br24.isExtern, true);
+  EXPECT_EQ(br24.symbol, 2U);
+  const Relocation& br14 = text.relocations[1];
+  EXPECT_EQ(br14.offset, Hex32(0x4));
+  EXPECT_EQ(br14.scattered, false);
+  EXPECT_EQ(br14.type, PPC_RELOC_BR14);
+  EXPECT_EQ(br14.pcRel, true);
+  EXPECT_EQ(br14.length, 2);
+  EXPECT_EQ(br14.isExtern, true);
+  EXPECT_EQ(br14.symbol, 2U);
+  const Relocation& pichi1 = text.relocations[2];
+  EXPECT_EQ(pichi1.offset, Hex32(0x8));
+  EXPECT_EQ(pichi1.scattered, true);
+  EXPECT_EQ(pichi1.type, PPC_RELOC_HI16_SECTDIFF);
+  EXPECT_EQ(pichi1.length, 2);
+  EXPECT_EQ(pichi1.value, 0x28U);
+  const Relocation& pichi2 = text.relocations[3];
+  EXPECT_EQ(pichi2.offset, Hex32(0x24));
+  EXPECT_EQ(pichi2.scattered, true);
+  EXPECT_EQ(pichi2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(pichi2.length, 2);
+  EXPECT_EQ(pichi2.value, 0x4U);
+  const Relocation& picha1 = text.relocations[4];
+  EXPECT_EQ(picha1.offset, Hex32(0xC));
+  EXPECT_EQ(picha1.scattered, true);
+  EXPECT_EQ(picha1.type, PPC_RELOC_HA16_SECTDIFF);
+  EXPECT_EQ(picha1.length, 2);
+  EXPECT_EQ(picha1.value, 0x28U);
+  const Relocation& picha2 = text.relocations[5];
+  EXPECT_EQ(picha2.offset, Hex32(0x24));
+  EXPECT_EQ(picha2.scattered, true);
+  EXPECT_EQ(picha2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(picha2.length, 2);
+  EXPECT_EQ(picha2.value, 0x4U);
+  const Relocation& piclo1 = text.relocations[6];
+  EXPECT_EQ(piclo1.offset, Hex32(0x10));
+  EXPECT_EQ(piclo1.scattered, true);
+  EXPECT_EQ(piclo1.type, PPC_RELOC_LO16_SECTDIFF);
+  EXPECT_EQ(piclo1.length, 2);
+  EXPECT_EQ(piclo1.value, 0x28U);
+  const Relocation& piclo2 = text.relocations[7];
+  EXPECT_EQ(piclo2.offset, Hex32(0x0));
+  EXPECT_EQ(piclo2.scattered, true);
+  EXPECT_EQ(piclo2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(piclo2.length, 2);
+  EXPECT_EQ(piclo2.value, 0x4U);
+  const Relocation& picloa1 = text.relocations[8];
+  EXPECT_EQ(picloa1.offset, Hex32(0x14));
+  EXPECT_EQ(picloa1.scattered, true);
+  EXPECT_EQ(picloa1.type, PPC_RELOC_LO14_SECTDIFF);
+  EXPECT_EQ(picloa1.length, 2);
+  EXPECT_EQ(picloa1.value, 0x28U);
+  const Relocation& picloa2 = text.relocations[9];
+  EXPECT_EQ(picloa2.offset, Hex32(0x0));
+  EXPECT_EQ(picloa2.scattered, true);
+  EXPECT_EQ(picloa2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(picloa2.length, 2);
+  EXPECT_EQ(picloa2.value, 0x4U);
+  const Relocation& abshi1 = text.relocations[10];
+  EXPECT_EQ(abshi1.offset, Hex32(0x18));
+  EXPECT_EQ(abshi1.scattered, false);
+  EXPECT_EQ(abshi1.type, PPC_RELOC_HI16);
+  EXPECT_EQ(abshi1.length, 2);
+  EXPECT_EQ(abshi1.symbol, 1U);
+  const Relocation& abshi2 = text.relocations[11];
+  EXPECT_EQ(abshi2.offset, Hex32(0x28));
+  EXPECT_EQ(abshi2.scattered, false);
+  EXPECT_EQ(abshi2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(abshi2.length, 2);
+  EXPECT_EQ(abshi2.symbol, 0U);
+  const Relocation& absha1 = text.relocations[12];
+  EXPECT_EQ(absha1.offset, Hex32(0x1C));
+  EXPECT_EQ(absha1.scattered, false);
+  EXPECT_EQ(absha1.type, PPC_RELOC_HA16);
+  EXPECT_EQ(absha1.length, 2);
+  EXPECT_EQ(absha1.symbol, 1U);
+  const Relocation& absha2 = text.relocations[13];
+  EXPECT_EQ(absha2.offset, Hex32(0x28));
+  EXPECT_EQ(absha2.scattered, false);
+  EXPECT_EQ(absha2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(absha2.length, 2);
+  EXPECT_EQ(absha2.symbol, 0U);
+  const Relocation& abslo1 = text.relocations[14];
+  EXPECT_EQ(abslo1.offset, Hex32(0x20));
+  EXPECT_EQ(abslo1.scattered, false);
+  EXPECT_EQ(abslo1.type, PPC_RELOC_LO16);
+  EXPECT_EQ(abslo1.length, 2);
+  EXPECT_EQ(abslo1.symbol, 1U);
+  const Relocation& abslo2 = text.relocations[15];
+  EXPECT_EQ(abslo2.offset, Hex32(0x00));
+  EXPECT_EQ(abslo2.scattered, false);
+  EXPECT_EQ(abslo2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(abslo2.length, 2);
+  EXPECT_EQ(abslo2.symbol, 0U);
+  const Relocation& absloa1 = text.relocations[16];
+  EXPECT_EQ(absloa1.offset, Hex32(0x24));
+  EXPECT_EQ(absloa1.scattered, false);
+  EXPECT_EQ(absloa1.type, PPC_RELOC_LO14);
+  EXPECT_EQ(absloa1.length, 2);
+  EXPECT_EQ(absloa1.symbol, 1U);
+  const Relocation& absloa2 = text.relocations[17];
+  EXPECT_EQ(absloa2.offset, Hex32(0x00));
+  EXPECT_EQ(absloa2.scattered, false);
+  EXPECT_EQ(absloa2.type, PPC_RELOC_PAIR);
+  EXPECT_EQ(absloa2.length, 2);
+  EXPECT_EQ(absloa2.symbol, 0U);
+ 
+  error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
+  EXPECT_FALSE(ec);
+}
+
+
+
+
+





More information about the llvm-commits mailing list