[lld] r192147 - Supoort mach-o encoded in yaml.

Nick Kledzik kledzik at apple.com
Mon Oct 7 17:43:34 PDT 2013


Author: kledzik
Date: Mon Oct  7 19:43:34 2013
New Revision: 192147

URL: http://llvm.org/viewvc/llvm-project?rev=192147&view=rev
Log:
Supoort mach-o encoded in yaml.

This is the first step in how I plan to get mach-o object files support into 
lld. We need to be able to test the mach-o Reader and Write on systems without 
a mach-o tools. Therefore, we want to support a textual way (YAML) to represent 
mach-o files.

MachONormalizedFile.h defines an in-memory abstraction of the content of mach-o  
files. The in-memory data structures are always native endianess and always
use 64-bit sizes. That internal data structure can then be converted to or
from three different formats: 1) yaml (text) encoded mach-o, 2) binary mach-o
files, 3) lld Atoms.

This patch defines the internal model and uses YAML I/O to implement the 
conversion to and from the model to yaml. The next patch will implement
the conversion from normalized to binary mach-o.

This patch includes unit tests to validate the yaml conversion APIs.

Added:
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
    lld/trunk/unittests/MachOTests/
    lld/trunk/unittests/MachOTests/CMakeLists.txt
    lld/trunk/unittests/MachOTests/MachONormalizedFileYAMLTests.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/unittests/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=192147&r1=192146&r2=192147&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Mon Oct  7 19:43:34 2013
@@ -47,6 +47,7 @@ public:
 
   enum Arch {
     arch_unknown,
+    arch_ppc,
     arch_x86,
     arch_x86_64,
     arch_armv6,
@@ -55,7 +56,7 @@ public:
   };
 
   enum class OS {
-    macOSX, iOS, iOS_simulator
+    unknown, macOSX, iOS, iOS_simulator
   };
 
   Arch arch() const { return _arch; }

Modified: lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt?rev=192147&r1=192146&r2=192147&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/MachO/CMakeLists.txt Mon Oct  7 19:43:34 2013
@@ -1,5 +1,6 @@
 add_lld_library(lldMachO
   MachOLinkingContext.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=192147&r1=192146&r2=192147&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Mon Oct  7 19:43:34 2013
@@ -149,20 +149,19 @@ bool MachOLinkingContext::outputTypeHasE
 }
 
 bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
+  uint32_t parsedVersion;
   switch (_os) {
-  case OS::macOSX: {
-    uint32_t parsedVersion;
+  case OS::macOSX:
     if (parsePackedVersion(mac, parsedVersion))
       return false;
     return _osMinVersion >= parsedVersion;
-  }
   case OS::iOS:
-  case OS::iOS_simulator: {
-    uint32_t parsedVersion;
+  case OS::iOS_simulator:
     if (parsePackedVersion(iOS, parsedVersion))
       return false;
     return _osMinVersion >= parsedVersion;
-  }
+  case OS::unknown:
+    break;
   }
   llvm_unreachable("target not configured for iOS or MacOSX");
 }

Added: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h?rev=192147&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h (added)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFile.h Mon Oct  7 19:43:34 2013
@@ -0,0 +1,279 @@
+//===- lib/ReaderWriter/MachO/NormalizedFile.h ----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+///
+/// \file These data structures comprise the "normalized" view of
+/// mach-o object files. The normalized view is an in-memory only data structure
+/// which is always in native endianness and pointer size. 
+///  
+/// The normalized view easily converts to and from YAML using YAML I/O. 
+///
+/// The normalized view converts to and from binary mach-o object files using
+/// the writeBinary() and readBinary() functions.
+///
+/// The normalized view converts to and from lld::Atoms using the 
+/// normalizedToAtoms() and normalizedFromAtoms().
+///
+/// Overall, the conversion paths available look like:
+///
+///                 +---------------+  
+///                 | binary mach-o |  
+///                 +---------------+  
+///                        ^
+///                        |
+///                        v
+///                  +------------+         +------+ 
+///                  | normalized |   <->   | yaml | 
+///                  +------------+         +------+ 
+///                        ^
+///                        |
+///                        v
+///                    +-------+ 
+///                    | Atoms |
+///                    +-------+ 
+/// 
+
+#include "lld/Core/Error.h"
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#ifndef LLD_READER_WRITER_MACHO_NORMALIZED_H_
+#define LLD_READER_WRITER_MACHO_NORMALIZED_H_
+
+using llvm::yaml::Hex64;
+using llvm::yaml::Hex32;
+using llvm::yaml::Hex8;
+using llvm::yaml::SequenceTraits;
+using llvm::MachO::HeaderFileType;
+using llvm::MachO::BindType;
+using llvm::MachO::RebaseType;
+using llvm::MachO::NListType;
+using llvm::MachO::RelocationInfoType;
+using llvm::MachO::SectionType;
+using llvm::MachO::LoadCommandType;
+using llvm::MachO::ExportSymbolKind;
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+
+/// The real mach-o relocation record is 8-bytes on disk and is
+/// encoded in one of two different bit-field patterns.  This
+/// normalized form has the union of all possbile fields.
+struct Relocation {
+  Relocation() : offset(0), scattered(false), 
+                 type(llvm::MachO::GENERIC_RELOC_VANILLA), 
+                 length(0), pcRel(false), isExtern(false), value(0), 
+                 symbol(0) { }
+
+  Hex32               offset;
+  bool                scattered;
+  RelocationInfoType  type;
+  uint8_t             length;
+  bool                pcRel;
+  bool                isExtern;
+  Hex32               value;
+  uint32_t            symbol;
+};
+
+/// A typedef so that YAML I/O can treat this vector as a sequence.
+typedef std::vector<Relocation> Relocations;
+
+/// A typedef so that YAML I/O can process the raw bytes in a section.
+typedef std::vector<Hex8> ContentBytes;
+
+/// A typedef so that YAML I/O can treat indirect symbols as a flow sequence.
+typedef std::vector<uint32_t> IndirectSymbols;
+
+/// A typedef so that YAML I/O can encode/decode section attributes.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr);
+
+/// Mach-O has a 32-bit and 64-bit section record.  This normalized form
+/// can support either kind.
+struct Section {
+  Section() : type(llvm::MachO::S_REGULAR), 
+              attributes(0), alignment(0), address(0) { }
+
+  StringRef       segmentName;
+  StringRef       sectionName;
+  SectionType     type;
+  SectionAttr     attributes;
+  uint32_t        alignment;
+  Hex64           address;
+  ContentBytes    content;
+  Relocations     relocations;
+  IndirectSymbols indirectSymbols;
+};
+
+
+/// A typedef so that YAML I/O can encode/decode the scope bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, SymbolScope);
+
+/// A typedef so that YAML I/O can encode/decode the desc bits of an nlist.
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, SymbolDesc);
+
+/// Mach-O has a 32-bit and 64-bit symbol table entry (nlist), and the symbol
+/// type and scope and mixed in the same n_type field.  This normalized form
+/// works for any pointer size and separates out the type and scope. 
+struct Symbol {
+  Symbol() : type(llvm::MachO::N_UNDF), scope(0), sect(0), desc(0), value(0) { }
+
+  StringRef     name;
+  NListType     type;
+  SymbolScope   scope;
+  uint8_t       sect;
+  SymbolDesc    desc;
+  Hex64         value;
+};
+
+/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect);
+
+/// Segments are only used in normalized final linked images (not in relocatable
+/// object files). They specify how a range of the file is loaded.
+struct Segment {
+  StringRef     name;
+  Hex64         address;
+  Hex64         size;
+  VMProtect     access;
+};
+
+/// Only used in normalized final linked images to specify on which dylibs
+/// it depends.
+struct DependentDylib {
+  StringRef       path;
+  LoadCommandType kind;
+};
+
+/// A normalized rebasing entry.  Only used in normalized final linked images.
+struct RebaseLocation {
+  Hex32         segOffset;
+  uint8_t       segIndex;
+  RebaseType    kind;
+};
+
+/// A normalized binding entry.  Only used in normalized final linked images.
+struct BindLocation {
+  Hex32           segOffset;
+  uint8_t         segIndex;
+  BindType        kind;
+  bool            canBeNull;
+  int             ordinal;
+  StringRef       symbolName;
+  Hex64           addend;
+};
+
+/// A typedef so that YAML I/O can encode/decode export flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportFlags);
+
+/// A normalized export entry.  Only used in normalized final linked images.
+struct Export {
+  StringRef         name;
+  Hex64             offset;
+  ExportSymbolKind  kind;
+  ExportFlags       flags;
+  Hex32             otherOffset;
+  StringRef         otherName;
+};
+
+
+/// A typedef so that YAML I/O can encode/decode mach_header.flags.
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags);
+
+/// 
+struct NormalizedFile {
+  NormalizedFile() : arch(MachOLinkingContext::arch_unknown), 
+                     fileType(llvm::MachO::MH_OBJECT),
+                     flags(0), 
+                     hasUUID(false), 
+                     os(MachOLinkingContext::OS::unknown) { }
+  
+  MachOLinkingContext::Arch   arch;
+  HeaderFileType              fileType;
+  FileFlags                   flags;
+  std::vector<Segment>        segments; // Not used in object files.
+  std::vector<Section>        sections;
+  
+  // Symbols sorted by kind.
+  std::vector<Symbol>         localSymbols;
+  std::vector<Symbol>         globalSymbols;
+  std::vector<Symbol>         undefinedSymbols;
+  
+  // Maps to load commands with no LINKEDIT content (final linked images only).
+  std::vector<DependentDylib> dependentDylibs;
+  StringRef                   installName;
+  bool                        hasUUID;
+  std::vector<StringRef>      rpaths;
+  Hex64                       entryAddress;
+  MachOLinkingContext::OS     os;
+  Hex64                       sourceVersion;
+  Hex32                       minOSverson;
+  Hex32                       sdkVersion;
+    
+  // Maps to load commands with LINKEDIT content (final linked images only).
+  std::vector<RebaseLocation> rebasingInfo;
+  std::vector<BindLocation>   bindingInfo;
+  std::vector<BindLocation>   weakBindingInfo;
+  std::vector<BindLocation>   lazyBindingInfo;
+  std::vector<Export>         exportInfo;
+  
+  // TODO:
+  // code-signature
+  // split-seg-info
+  // function-starts
+  // data-in-code
+};
+
+
+/// Reads a mach-o file and produces an in-memory normalized view.
+ErrorOr<std::unique_ptr<NormalizedFile>> 
+readBinary(std::unique_ptr<MemoryBuffer> &mb);
+
+/// Takes in-memory normalized view and writes a mach-o object file.
+error_code 
+writeBinary(const NormalizedFile &file, StringRef path);
+
+size_t headerAndLoadCommandsSize(const NormalizedFile &file);
+
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+ErrorOr<std::unique_ptr<NormalizedFile>> 
+readYaml(std::unique_ptr<MemoryBuffer> &mb);
+
+/// Writes a yaml encoded mach-o files given an in-memory normalized view.
+error_code 
+writeYaml(const NormalizedFile &file, llvm::raw_ostream &out);
+
+
+/// Takes in-memory normalized dylib or object and parses it into lld::File
+ErrorOr<std::unique_ptr<lld::File>> 
+normalizedToAtoms(const NormalizedFile &normalizedFile);
+
+/// Takes atoms and generates a normalized macho-o view.
+ErrorOr<std::unique_ptr<NormalizedFile>> 
+normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
+
+
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_NORMALIZED_H_
+
+
+
+

Added: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp?rev=192147&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp (added)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp Mon Oct  7 19:43:34 2013
@@ -0,0 +1,650 @@
+//===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.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 uses YAML I/O to
+/// provide the convert between YAML and the normalized mach-o (NM).
+///
+///                  +------------+         +------+ 
+///                  | normalized |   <->   | yaml | 
+///                  +------------+         +------+ 
+
+#include "MachONormalizedFile.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/MachO.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/YAMLTraits.h"
+
+
+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;
+
+// A vector of Sections is a sequence.
+template<>
+struct SequenceTraits< std::vector<Section> > {
+  static size_t size(IO &io, std::vector<Section> &seq) {
+    return seq.size();
+  }
+  static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+template<>
+struct SequenceTraits< std::vector<Symbol> > {
+  static size_t size(IO &io, std::vector<Symbol> &seq) {
+    return seq.size();
+  }
+  static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+// A vector of Relocations is a sequence.
+template<>
+struct SequenceTraits< Relocations > {
+  static size_t size(IO &io, Relocations &seq) {
+    return seq.size();
+  }
+  static Relocation& element(IO &io, Relocations &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+};
+
+// The content for a section is represented as a flow sequence of hex bytes.
+template<>
+struct SequenceTraits< ContentBytes > {
+  static size_t size(IO &io, ContentBytes &seq) {
+    return seq.size();
+  }
+  static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+  static const bool flow = true;
+};
+
+// The indirect symbols for a section is represented as a flow sequence 
+// of numbers (symbol table indexes).
+template<>
+struct SequenceTraits< IndirectSymbols > {
+  static size_t size(IO &io, IndirectSymbols &seq) {
+    return seq.size();
+  }
+  static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
+    if ( index >= seq.size() )
+      seq.resize(index+1);
+    return seq[index];
+  }
+  static const bool flow = true;
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
+  static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
+    io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
+    io.enumCase(value, "ppc",    lld::MachOLinkingContext::arch_ppc);
+    io.enumCase(value, "x86",    lld::MachOLinkingContext::arch_x86);
+    io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
+    io.enumCase(value, "armv6",  lld::MachOLinkingContext::arch_armv6);
+    io.enumCase(value, "armv7",  lld::MachOLinkingContext::arch_armv7);
+    io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
+  static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
+    io.enumCase(value, "unknown",    
+                          lld::MachOLinkingContext::OS::unknown);
+    io.enumCase(value, "Mac OS X",    
+                          lld::MachOLinkingContext::OS::macOSX);
+    io.enumCase(value, "iOS",         
+                          lld::MachOLinkingContext::OS::iOS);
+    io.enumCase(value, "iOS Simulator", 
+                          lld::MachOLinkingContext::OS::iOS_simulator);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<HeaderFileType> {
+  static void enumeration(IO &io, HeaderFileType &value) {
+    io.enumCase(value, "object",      llvm::MachO::MH_OBJECT);
+    io.enumCase(value, "dylib",       llvm::MachO::MH_DYLIB);
+    io.enumCase(value, "executable",  llvm::MachO::MH_EXECUTE);
+    io.enumCase(value, "bundle",      llvm::MachO::MH_BUNDLE);
+  }
+};
+
+
+template <>
+struct ScalarBitSetTraits<FileFlags> {
+  static void bitset(IO &io, FileFlags &value) {
+    io.bitSetCase(value, "MH_TWOLEVEL", 
+                          llvm::MachO::MH_TWOLEVEL);
+    io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",  
+                          llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<SectionType> {
+  static void enumeration(IO &io, SectionType &value) {
+    io.enumCase(value, "S_REGULAR",  
+                        llvm::MachO::S_REGULAR);
+    io.enumCase(value, "S_ZEROFILL", 
+                        llvm::MachO::S_ZEROFILL);
+    io.enumCase(value, "S_CSTRING_LITERALS", 
+                        llvm::MachO::S_CSTRING_LITERALS);
+    io.enumCase(value, "S_4BYTE_LITERALS", 
+                        llvm::MachO::S_4BYTE_LITERALS);
+    io.enumCase(value, "S_8BYTE_LITERALS", 
+                        llvm::MachO::S_8BYTE_LITERALS);
+    io.enumCase(value, "S_LITERAL_POINTERS", 
+                        llvm::MachO::S_LITERAL_POINTERS);
+    io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS", 
+                        llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
+    io.enumCase(value, "S_LAZY_SYMBOL_POINTERS", 
+                        llvm::MachO::S_LAZY_SYMBOL_POINTERS);
+    io.enumCase(value, "S_SYMBOL_STUBS", 
+                        llvm::MachO::S_SYMBOL_STUBS);
+    io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS", 
+                        llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
+    io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS", 
+                        llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
+    io.enumCase(value, "S_COALESCED", 
+                        llvm::MachO::S_COALESCED);
+    io.enumCase(value, "S_GB_ZEROFILL", 
+                        llvm::MachO::S_GB_ZEROFILL);
+    io.enumCase(value, "S_INTERPOSING", 
+                        llvm::MachO::S_INTERPOSING);
+    io.enumCase(value, "S_16BYTE_LITERALS", 
+                        llvm::MachO::S_16BYTE_LITERALS);
+    io.enumCase(value, "S_DTRACE_DOF", 
+                        llvm::MachO::S_DTRACE_DOF);
+    io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS", 
+                        llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
+    io.enumCase(value, "S_THREAD_LOCAL_REGULAR", 
+                        llvm::MachO::S_THREAD_LOCAL_REGULAR);
+    io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL", 
+                        llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
+    io.enumCase(value, "S_THREAD_LOCAL_VARIABLES", 
+                        llvm::MachO::S_THREAD_LOCAL_VARIABLES);
+    io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS", 
+                        llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
+    io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS", 
+                        llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SectionAttr> {
+  static void bitset(IO &io, SectionAttr &value) {
+    io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS", 
+                          llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
+    io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",  
+                          llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
+    io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",  
+                          llvm::MachO::S_ATTR_NO_DEAD_STRIP);
+    io.bitSetCase(value, "S_ATTR_EXT_RELOC",  
+                          llvm::MachO::S_ATTR_EXT_RELOC);
+    io.bitSetCase(value, "S_ATTR_LOC_RELOC",  
+                          llvm::MachO::S_ATTR_LOC_RELOC);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<NListType> {
+  static void enumeration(IO &io, NListType &value) {
+    io.enumCase(value, "N_UNDF",  llvm::MachO::N_UNDF);
+    io.enumCase(value, "N_ABS",   llvm::MachO::N_ABS);
+    io.enumCase(value, "N_SECT",  llvm::MachO::N_SECT);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolScope> {
+  static void bitset(IO &io, SymbolScope &value) {
+    io.bitSetCase(value, "N_EXT",   llvm::MachO::N_EXT);
+    io.bitSetCase(value, "N_PEXT",  llvm::MachO::N_PEXT);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<SymbolDesc> {
+  static void bitset(IO &io, SymbolDesc &value) {
+    io.bitSetCase(value, "N_NO_DEAD_STRIP",   llvm::MachO::N_NO_DEAD_STRIP);
+    io.bitSetCase(value, "N_WEAK_REF",        llvm::MachO::N_WEAK_REF);
+    io.bitSetCase(value, "N_WEAK_DEF",        llvm::MachO::N_WEAK_DEF);
+    io.bitSetCase(value, "N_ARM_THUMB_DEF",   llvm::MachO::N_ARM_THUMB_DEF);
+    io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
+  }
+};
+
+
+template <>
+struct MappingTraits<Section> {
+  static void mapping(IO &io, Section &sect) {
+    io.mapRequired("segment",         sect.segmentName);
+    io.mapRequired("section",         sect.sectionName);
+    io.mapRequired("type",            sect.type);
+    io.mapOptional("attributes",      sect.attributes);
+    io.mapOptional("alignment",       sect.alignment, 0U);
+    io.mapRequired("address",         sect.address);
+    io.mapOptional("content",         sect.content);
+    io.mapOptional("relocations",     sect.relocations);
+    io.mapOptional("indirect-syms",   sect.indirectSymbols);
+  }
+};
+
+
+template <>
+struct MappingTraits<Relocation> {
+  static void mapping(IO &io, Relocation &reloc) {
+    io.mapRequired("offset",    reloc.offset);
+    io.mapOptional("scattered", reloc.scattered, false);
+    io.mapRequired("type",      reloc.type);
+    io.mapRequired("length",    reloc.length);
+    io.mapRequired("pc-rel",    reloc.pcRel);
+    if ( !reloc.scattered )
+     io.mapRequired("extern",   reloc.isExtern);
+    if ( reloc.scattered )
+     io.mapRequired("value",    reloc.value);
+    if ( !reloc.scattered )
+     io.mapRequired("symbol",   reloc.symbol);
+  }
+};
+
+
+template <>
+struct ScalarEnumerationTraits<RelocationInfoType> {
+  static void enumeration(IO &io, RelocationInfoType &value) {
+    NormalizedFile *file = reinterpret_cast<NormalizedFile*>(io.getContext());
+    assert(file != nullptr);
+    switch (file->arch) {
+    case lld::MachOLinkingContext::arch_x86_64:
+      io.enumCase(value, "X86_64_RELOC_UNSIGNED",  
+                                  llvm::MachO::X86_64_RELOC_UNSIGNED);
+      io.enumCase(value, "X86_64_RELOC_SIGNED",   
+                                  llvm::MachO::X86_64_RELOC_SIGNED);
+      io.enumCase(value, "X86_64_RELOC_BRANCH",    
+                                  llvm::MachO::X86_64_RELOC_BRANCH);
+      io.enumCase(value, "X86_64_RELOC_GOT_LOAD",    
+                                  llvm::MachO::X86_64_RELOC_GOT_LOAD);
+      io.enumCase(value, "X86_64_RELOC_GOT",    
+                                  llvm::MachO::X86_64_RELOC_GOT);
+      io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",   
+                                  llvm::MachO::X86_64_RELOC_SUBTRACTOR);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_1",    
+                                  llvm::MachO::X86_64_RELOC_SIGNED_1);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_2",    
+                                  llvm::MachO::X86_64_RELOC_SIGNED_2);
+      io.enumCase(value, "X86_64_RELOC_SIGNED_4",    
+                                  llvm::MachO::X86_64_RELOC_SIGNED_4);
+      io.enumCase(value, "X86_64_RELOC_TLV",    
+                                  llvm::MachO::X86_64_RELOC_TLV);
+      break;
+    case lld::MachOLinkingContext::arch_x86:
+      io.enumCase(value, "GENERIC_RELOC_VANILLA",  
+                                  llvm::MachO::GENERIC_RELOC_VANILLA);
+      io.enumCase(value, "GENERIC_RELOC_PAIR",   
+                                  llvm::MachO::GENERIC_RELOC_PAIR);
+      io.enumCase(value, "GENERIC_RELOC_SECTDIFF",  
+                                  llvm::MachO::GENERIC_RELOC_SECTDIFF);
+      io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",   
+                                  llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+      io.enumCase(value, "GENERIC_RELOC_TLV",   
+                                  llvm::MachO::GENERIC_RELOC_TLV);
+      break;
+    case lld::MachOLinkingContext::arch_armv6:
+    case lld::MachOLinkingContext::arch_armv7:
+    case lld::MachOLinkingContext::arch_armv7s:
+       io.enumCase(value, "ARM_RELOC_VANILLA",  
+                                  llvm::MachO::ARM_RELOC_VANILLA);
+      io.enumCase(value, "ARM_RELOC_PAIR",   
+                                  llvm::MachO::ARM_RELOC_PAIR);
+      io.enumCase(value, "ARM_RELOC_SECTDIFF",  
+                                  llvm::MachO::ARM_RELOC_SECTDIFF);
+      io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",   
+                                  llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
+      io.enumCase(value, "ARM_RELOC_BR24",   
+                                  llvm::MachO::ARM_RELOC_BR24);
+      io.enumCase(value, "ARM_THUMB_RELOC_BR22",   
+                                  llvm::MachO::ARM_THUMB_RELOC_BR22);
+      io.enumCase(value, "ARM_RELOC_HALF",   
+                                  llvm::MachO::ARM_RELOC_HALF);
+      io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",   
+                                  llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+      break;
+    default:
+      llvm_unreachable("unknown archictecture");
+    }
+ }
+};
+
+
+template <>
+struct MappingTraits<Symbol> {
+  static void mapping(IO &io, Symbol& sym) {
+    io.mapRequired("name",    sym.name);
+    io.mapRequired("type",    sym.type);
+    io.mapOptional("scope",   sym.scope, SymbolScope(0));
+    io.mapOptional("sect",    sym.sect, (uint8_t)0);
+    io.mapOptional("desc",    sym.desc, SymbolDesc(0));
+    io.mapRequired("value",   sym.value);
+  }
+};
+
+// Custom mapping for VMProtect (e.g. "r-x").
+template <>
+struct ScalarTraits<VMProtect> {
+  static void output(const VMProtect &value, void*, llvm::raw_ostream &out) {
+    out << ( (value & llvm::MachO::VM_PROT_READ)    ? 'r' : '-');
+    out << ( (value & llvm::MachO::VM_PROT_WRITE)   ? 'w' : '-');
+    out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
+  }
+  static StringRef input(StringRef scalar, void*, VMProtect &value) {
+    value = 0;
+    if (scalar.size() != 3)
+      return "segment access protection must be three chars (e.g. \"r-x\")";
+    switch (scalar[0]) {
+    case 'r':
+      value = llvm::MachO::VM_PROT_READ;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection first char must be 'r' or '-'";
+    }
+    switch (scalar[1]) {
+    case 'w':
+      value = value | llvm::MachO::VM_PROT_WRITE;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection second char must be 'w' or '-'";
+    }
+    switch (scalar[2]) {
+    case 'x':
+      value = value | llvm::MachO::VM_PROT_EXECUTE;
+      break;
+    case '-':
+      break;
+    default:
+      return "segment access protection third char must be 'x' or '-'";
+    }
+    // Return the empty string on success,
+    return StringRef();
+  }
+};
+
+
+template <>
+struct MappingTraits<Segment> {
+  static void mapping(IO &io, Segment& seg) {
+    io.mapRequired("name",      seg.name);
+    io.mapRequired("address",   seg.address);
+    io.mapRequired("size",      seg.size);
+    io.mapRequired("access",    seg.access);
+  }
+};
+LLVM_YAML_IS_SEQUENCE_VECTOR(Segment);
+
+template <>
+struct ScalarEnumerationTraits<LoadCommandType> {
+  static void enumeration(IO &io, LoadCommandType &value) {
+    io.enumCase(value, "LC_LOAD_DYLIB",  
+                        llvm::MachO::LC_LOAD_DYLIB);
+    io.enumCase(value, "LC_LOAD_WEAK_DYLIB",  
+                        llvm::MachO::LC_LOAD_WEAK_DYLIB);
+    io.enumCase(value, "LC_REEXPORT_DYLIB",  
+                        llvm::MachO::LC_REEXPORT_DYLIB);
+    io.enumCase(value, "LC_LOAD_UPWARD_DYLIB", 
+                        llvm::MachO::LC_LOAD_UPWARD_DYLIB);
+    io.enumCase(value, "LC_LAZY_LOAD_DYLIB",  
+                        llvm::MachO::LC_LAZY_LOAD_DYLIB);
+  }
+};
+
+template <>
+struct MappingTraits<DependentDylib> {
+  static void mapping(IO &io, DependentDylib& dylib) {
+    io.mapRequired("path",    dylib.path);
+    io.mapOptional("kind",    dylib.kind,       llvm::MachO::LC_LOAD_DYLIB);
+  }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib);
+
+template <>
+struct ScalarEnumerationTraits<RebaseType> {
+  static void enumeration(IO &io, RebaseType &value) {
+    io.enumCase(value, "REBASE_TYPE_POINTER",  
+                        llvm::MachO::REBASE_TYPE_POINTER);
+    io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",  
+                        llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
+    io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",  
+                        llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
+  }
+};
+
+
+template <>
+struct MappingTraits<RebaseLocation> {
+  static void mapping(IO &io, RebaseLocation& rebase) {
+    io.mapRequired("segment-index",   rebase.segIndex);
+    io.mapRequired("segment-offset",  rebase.segOffset);
+    io.mapOptional("kind",            rebase.kind, 
+                                      llvm::MachO::REBASE_TYPE_POINTER);
+  }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation);
+
+template <>
+struct ScalarEnumerationTraits<BindType> {
+  static void enumeration(IO &io, BindType &value) {
+    io.enumCase(value, "BIND_TYPE_POINTER",  
+                        llvm::MachO::BIND_TYPE_POINTER);
+    io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",  
+                        llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
+    io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",  
+                        llvm::MachO::BIND_TYPE_TEXT_PCREL32);
+  }
+};
+
+template <>
+struct MappingTraits<BindLocation> {
+  static void mapping(IO &io, BindLocation &bind) {
+    io.mapRequired("segment-index",   bind.segIndex);
+    io.mapRequired("segment-offset",  bind.segOffset);
+    io.mapOptional("kind",            bind.kind, 
+                                      llvm::MachO::BIND_TYPE_POINTER);
+    io.mapOptional("can-be-null",     bind.canBeNull, false);
+    io.mapRequired("ordinal",         bind.ordinal);
+    io.mapRequired("symbol-name",     bind.symbolName);
+    io.mapOptional("addend",          bind.addend, Hex64(0));
+  }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation);
+
+
+template <>
+struct ScalarEnumerationTraits<ExportSymbolKind> {
+  static void enumeration(IO &io, ExportSymbolKind &value) {
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",       
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+    io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCALl",  
+                        llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+  }
+};
+
+template <>
+struct ScalarBitSetTraits<ExportFlags> {
+  static void bitset(IO &io, ExportFlags &value) {
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",   
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",         
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+    io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",    
+                          llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+  }
+};
+
+
+template <>
+struct MappingTraits<Export> {
+  static void mapping(IO &io, Export &exp) {
+    io.mapRequired("name",         exp.name);
+    io.mapRequired("offset",       exp.offset);
+    io.mapOptional("kind",         exp.kind, 
+                                llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
+    io.mapOptional("flags",        exp.flags);
+    io.mapOptional("other-offset", exp.otherOffset, Hex32(0));
+    io.mapOptional("other-name",   exp.otherName, StringRef());
+  }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(Export);
+LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef);
+
+template <>
+struct MappingTraits<NormalizedFile> {
+  static void mapping(IO &io, NormalizedFile &file) {
+    io.mapRequired("arch",             file.arch);
+    io.mapRequired("file-type",        file.fileType);
+    io.mapOptional("flags",            file.flags);
+    io.mapOptional("dependents",       file.dependentDylibs);
+    io.mapOptional("install-name",     file.installName,    StringRef());
+    io.mapOptional("has-UUID",         file.hasUUID,        true);
+    io.mapOptional("rpaths",           file.rpaths);
+    io.mapOptional("entry-point",      file.entryAddress,   Hex64(0));
+    io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
+    io.mapOptional("OS",               file.os);
+    io.mapOptional("min-os-version",   file.minOSverson,    Hex32(0));
+    io.mapOptional("sdk-version",      file.sdkVersion,     Hex32(0));
+    io.mapOptional("segments",         file.segments);
+    io.mapOptional("sections",         file.sections);
+    io.mapOptional("local-symbols",    file.localSymbols);
+    io.mapOptional("global-symbols",   file.globalSymbols);
+    io.mapOptional("undefined-symbols",file.undefinedSymbols);
+    io.mapOptional("rebasings",        file.rebasingInfo);
+    io.mapOptional("bindings",         file.bindingInfo);
+    io.mapOptional("weak-bindings",    file.weakBindingInfo);
+    io.mapOptional("lazy-bindings",    file.lazyBindingInfo);
+    io.mapOptional("exports",          file.exportInfo);
+  }
+};
+
+
+namespace lld {
+namespace mach_o {
+namespace normalized {
+
+/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
+ErrorOr<std::unique_ptr<NormalizedFile>> 
+readYaml(std::unique_ptr<MemoryBuffer> &mb) {
+  // Make empty NormalizedFile.
+  std::unique_ptr<NormalizedFile> f(new NormalizedFile());
+
+  // Create YAML Input parser.
+  llvm::yaml::Input yin(mb->getBuffer(), f.get());
+
+  // Fill NormalizedFile by parsing yaml.
+  yin >> *f;
+
+  // Return error if there were parsing problems.
+  if (yin.error())
+    return make_error_code(lld::yaml_reader_error::illegal_value);
+
+  // Hand ownership of instantiated NormalizedFile to caller.
+  return std::move(f);
+}
+
+
+/// Writes a yaml encoded mach-o files from an in-memory normalized view.
+error_code 
+writeYaml(const NormalizedFile &file, llvm::raw_ostream &out) {
+  // YAML I/O is not const aware, so need to cast away ;-(
+  NormalizedFile *f = const_cast<NormalizedFile*>(&file);
+
+  // Create yaml Output writer, using yaml options for context.
+  llvm::yaml::Output yout(out, f);
+
+  // Stream out yaml.
+  yout << *f;
+
+  return error_code::success();
+}
+
+} // namespace normalized
+} // namespace mach_o
+} // namespace lld
+

Modified: lld/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/CMakeLists.txt?rev=192147&r1=192146&r2=192147&view=diff
==============================================================================
--- lld/trunk/unittests/CMakeLists.txt (original)
+++ lld/trunk/unittests/CMakeLists.txt Mon Oct  7 19:43:34 2013
@@ -12,3 +12,4 @@ endfunction()
 
 add_subdirectory(CoreTests)
 add_subdirectory(DriverTests)
+add_subdirectory(MachOTests)

Added: lld/trunk/unittests/MachOTests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/MachOTests/CMakeLists.txt?rev=192147&view=auto
==============================================================================
--- lld/trunk/unittests/MachOTests/CMakeLists.txt (added)
+++ lld/trunk/unittests/MachOTests/CMakeLists.txt Mon Oct  7 19:43:34 2013
@@ -0,0 +1,9 @@
+
+add_lld_unittest(lldMachOTests
+  MachONormalizedFileYAMLTests.cpp
+  )
+
+target_link_libraries(lldMachOTests
+  lldMachO
+  lldYAML
+  )

Added: lld/trunk/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp?rev=192147&view=auto
==============================================================================
--- lld/trunk/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp (added)
+++ lld/trunk/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp Mon Oct  7 19:43:34 2013
@@ -0,0 +1,769 @@
+//===- lld/unittest/MachOTests/MachONormalizedFileYAMLTests.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 lld::mach_o::normalized::NormalizedFile;
+using lld::mach_o::normalized::Symbol;
+using lld::mach_o::normalized::Section;
+using lld::mach_o::normalized::Relocation;
+
+
+static std::unique_ptr<NormalizedFile> fromYAML(StringRef str) {
+  std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(str));
+  ErrorOr<std::unique_ptr<NormalizedFile>> r 
+                                    = lld::mach_o::normalized::readYaml(mb);
+  EXPECT_FALSE(!r);
+  return std::move(*r);
+}
+
+static void toYAML(const NormalizedFile &f, std::string &out) {
+  llvm::raw_string_ostream ostr(out);
+  llvm::error_code ec = lld::mach_o::normalized::writeYaml(f, ostr);
+  EXPECT_TRUE(!ec);
+}
+
+
+// ppc is no longer supported, but it is here to test endianness handling.
+TEST(ObjectFileYAML, empty_ppc) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      ppc\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_ppc);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86_64) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_x86) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv6) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv6\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+TEST(ObjectFileYAML, empty_armv7s) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7s\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7s);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+}
+
+
+TEST(ObjectFileYAML, roundTrip) {
+  std::string intermediate;  
+  {
+    NormalizedFile f;
+    f.arch = lld::MachOLinkingContext::arch_x86_64;
+    f.fileType = llvm::MachO::MH_OBJECT;
+    f.flags = llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+    f.os = lld::MachOLinkingContext::OS::macOSX;
+    toYAML(f, intermediate);
+  }
+  {
+    std::unique_ptr<NormalizedFile> f2 = fromYAML(intermediate);
+    EXPECT_EQ(f2->arch, lld::MachOLinkingContext::arch_x86_64);
+    EXPECT_EQ((int)(f2->fileType), llvm::MachO::MH_OBJECT);
+    EXPECT_EQ((int)(f2->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+    EXPECT_TRUE(f2->sections.empty());
+    EXPECT_TRUE(f2->localSymbols.empty());
+    EXPECT_TRUE(f2->globalSymbols.empty());
+    EXPECT_TRUE(f2->undefinedSymbols.empty());
+  }
+}
+
+
+TEST(ObjectFileYAML, oneSymbol) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: object\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    desc:   [ ]\n"
+    "    value:  0x100\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_TRUE(f->sections.empty());
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym = f->globalSymbols[0];
+  EXPECT_TRUE(sym.name.equals("_main"));
+  EXPECT_EQ((int)(sym.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym.sect, 1);
+  EXPECT_EQ((int)(sym.desc), 0);
+  EXPECT_EQ((uint64_t)sym.value, 0x100ULL);
+}
+
+
+TEST(ObjectFileYAML, oneSection) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: object\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS ]\n"
+    "    alignment:   1\n"
+    "    address:     0x12345678\n"
+    "    content:     [ 0x90, 0x90 ]\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_TRUE(f->localSymbols.empty());
+  EXPECT_TRUE(f->globalSymbols.empty());
+  EXPECT_TRUE(f->undefinedSymbols.empty());
+  EXPECT_EQ(f->sections.size(), 1UL);
+  const Section& sect = f->sections[0];
+  EXPECT_TRUE(sect.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect.attributes), 
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS));
+  EXPECT_EQ(sect.alignment, 1U);
+  EXPECT_EQ(sect.address, 0x12345678ULL);
+  EXPECT_EQ(sect.content.size(), 2UL);
+  EXPECT_EQ((int)(sect.content[0]), 0x90);
+  EXPECT_EQ((int)(sect.content[1]), 0x90);
+}
+
+
+TEST(ObjectFileYAML, hello_x86_64) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86_64\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   0\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x55, 0x48, 0x89, 0xe5, 0x48, 0x8d, 0x3d, 0x00,\n"
+    "                   0x00, 0x00, 0x00, 0x30, 0xc0, 0xe8, 0x00, 0x00,\n"
+    "                   0x00, 0x00, 0x31, 0xc0, 0x5d, 0xc3 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x0e\n"
+    "       type:       X86_64_RELOC_BRANCH\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     2\n"
+    "     - offset:     0x07\n"
+    "       type:       X86_64_RELOC_SIGNED\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   0\n"
+    "    address:     0x0016\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "local-symbols:\n"
+    "  - name:   L_.str\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ ]\n"
+    "    sect:   2\n"
+    "    value:  0x16\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86_64);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes), 
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS 
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(sect1.alignment, 0U);
+  EXPECT_EQ(sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 22UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x55);
+  EXPECT_EQ((int)(sect1.content[1]), 0x48);
+  EXPECT_EQ(sect1.relocations.size(), 2UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x0eU);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::X86_64_RELOC_BRANCH);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 2U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x07U);
+  EXPECT_FALSE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::X86_64_RELOC_SIGNED);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_TRUE(reloc2.pcRel);
+  EXPECT_TRUE(reloc2.isExtern);
+  EXPECT_EQ(reloc2.symbol, 1U);
+  EXPECT_EQ((int)(reloc2.value), 0);
+ 
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ(sect2.alignment, 0U);
+  EXPECT_EQ(sect2.address, 0x016ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+  
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->localSymbols.size(), 1UL);
+  const Symbol& sym2 = f->localSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("L_.str"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 2);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x16ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym3 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym3.name.equals("_printf"));
+  EXPECT_EQ((int)(sym3.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym3.scope), 0);
+  EXPECT_EQ(sym3.sect, 0);
+  EXPECT_EQ((int)(sym3.desc), 0);
+  EXPECT_EQ((uint64_t)sym3.value, 0x0ULL);
+}
+
+
+TEST(ObjectFileYAML, hello_x86) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      x86\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   0\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08, 0xe8, 0x00,\n"
+    "                   0x00, 0x00, 0x00, 0x58, 0x8d, 0x80, 0x16, 0x00,\n"
+    "                   0x00, 0x00, 0x89, 0x04, 0x24, 0xe8, 0xe6, 0xff,\n"
+    "                   0xff, 0xff, 0x31, 0xc0, 0x83, 0xc4, 0x08, 0x5d,\n"
+    "                   0xc3 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x16\n"
+    "       type:       GENERIC_RELOC_VANILLA\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "     - offset:     0x0e\n"
+    "       scattered:  true\n"
+    "       type:       GENERIC_RELOC_LOCAL_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x21\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       GENERIC_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xb\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   0\n"
+    "    address:     0x0021\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_x86);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes), 
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS 
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(sect1.alignment, 0U);
+  EXPECT_EQ(sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 33UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x55);
+  EXPECT_EQ((int)(sect1.content[1]), 0x89);
+  EXPECT_EQ(sect1.relocations.size(), 3UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x16U);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::GENERIC_RELOC_VANILLA);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 1U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x0eU);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0x21);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0U);
+  EXPECT_TRUE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::GENERIC_RELOC_PAIR);
+  EXPECT_EQ(reloc3.length, 2);
+  EXPECT_FALSE(reloc3.pcRel);
+  EXPECT_EQ(reloc3.symbol, 0U);
+  EXPECT_EQ((int)(reloc3.value), 0xb);
+ 
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ(sect2.alignment, 0U);
+  EXPECT_EQ(sect2.address, 0x021ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+  
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+TEST(ObjectFileYAML, hello_armv6) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv6\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   2\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x80, 0x40, 0x2d, 0xe9, 0x10, 0x00, 0x9f, 0xe5,\n"
+    "                   0x0d, 0x70, 0xa0, 0xe1, 0x00, 0x00, 0x8f, 0xe0,\n"
+    "                   0xfa, 0xff, 0xff, 0xeb, 0x00, 0x00, 0xa0, 0xe3,\n"
+    "                   0x80, 0x80, 0xbd, 0xe8, 0x0c, 0x00, 0x00, 0x00 ]\n"
+    "    relocations:\n"
+    "     - offset:     0x1c\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x20\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "     - offset:     0x10\n"
+    "       type:       ARM_RELOC_BR24\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   0\n"
+    "    address:     0x0020\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv6);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes), 
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS 
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(sect1.alignment, 2U);
+  EXPECT_EQ(sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 32UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x80);
+  EXPECT_EQ((int)(sect1.content[1]), 0x40);
+  EXPECT_EQ(sect1.relocations.size(), 3UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x1cU);
+  EXPECT_TRUE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_RELOC_SECTDIFF);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_FALSE(reloc1.pcRel);
+  EXPECT_EQ(reloc1.symbol, 0U);
+  EXPECT_EQ((int)(reloc1.value), 0x20);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x0U);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc2.length, 2);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0xc);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0x10U);
+  EXPECT_FALSE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_BR24);
+  EXPECT_EQ(reloc3.length, 2);
+  EXPECT_TRUE(reloc3.pcRel);
+  EXPECT_TRUE(reloc3.isExtern);
+  EXPECT_EQ(reloc3.symbol, 1U);
+  EXPECT_EQ((int)(reloc3.value), 0);
+ 
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ(sect2.alignment, 0U);
+  EXPECT_EQ(sect2.address, 0x020ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+  
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), 0);
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}
+
+
+
+TEST(ObjectFileYAML, hello_armv7) {
+  std::unique_ptr<NormalizedFile> f = fromYAML(
+    "---\n"
+    "arch:      armv7\n"
+    "file-type: object\n"
+    "flags:     [ MH_SUBSECTIONS_VIA_SYMBOLS ]\n"
+    "sections:\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __text\n"
+    "    type:        S_REGULAR\n"
+    "    attributes:  [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS]\n"
+    "    alignment:   1\n"
+    "    address:     0x0000\n"
+    "    content:     [ 0x80, 0xb5, 0x40, 0xf2, 0x06, 0x00, 0x6f, 0x46,\n"
+    "                   0xc0, 0xf2, 0x00, 0x00, 0x78, 0x44, 0xff, 0xf7,\n"
+    "                   0xf8, 0xef, 0x00, 0x20, 0x80, 0xbd ]\n"
+    "    relocations:\n"
+    "     - offset:     0x0e\n"
+    "       type:       ARM_THUMB_RELOC_BR22\n"
+    "       length:     2\n"
+    "       pc-rel:     true\n"
+    "       extern:     true\n"
+    "       symbol:     1\n"
+    "     - offset:     0x08\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_HALF_SECTDIFF\n"
+    "       length:     3\n"
+    "       pc-rel:     false\n"
+    "       value:      0x16\n"
+    "     - offset:     0x06\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     3\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "     - offset:     0x02\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_HALF_SECTDIFF\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0x16\n"
+    "     - offset:     0x0\n"
+    "       scattered:  true\n"
+    "       type:       ARM_RELOC_PAIR\n"
+    "       length:     2\n"
+    "       pc-rel:     false\n"
+    "       value:      0xc\n"
+    "  - segment:     __TEXT\n"
+    "    section:     __cstring\n"
+    "    type:        S_CSTRING_LITERALS\n"
+    "    attributes:  [ ]\n"
+    "    alignment:   0\n"
+    "    address:     0x0016\n"
+    "    content:     [ 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x00 ]\n"
+    "global-symbols:\n"
+    "  - name:   _main\n"
+    "    type:   N_SECT\n"
+    "    scope:  [ N_EXT ]\n"
+    "    sect:   1\n"
+    "    desc:   [ N_ARM_THUMB_DEF ]\n"
+    "    value:  0x0\n"
+    "undefined-symbols:\n"
+    "  - name:   _printf\n"
+    "    type:   N_UNDF\n"
+    "    value:  0x0\n"
+    "...\n");
+  EXPECT_EQ(f->arch, lld::MachOLinkingContext::arch_armv7);
+  EXPECT_EQ(f->fileType, llvm::MachO::MH_OBJECT);
+  EXPECT_EQ((int)(f->flags), llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
+  EXPECT_EQ(f->sections.size(), 2UL);
+  
+  const Section& sect1 = f->sections[0];
+  EXPECT_TRUE(sect1.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect1.sectionName.equals("__text"));
+  EXPECT_EQ((uint32_t)(sect1.type), (uint32_t)(llvm::MachO::S_REGULAR));
+  EXPECT_EQ((uint32_t)(sect1.attributes), 
+                            (uint32_t)(llvm::MachO::S_ATTR_PURE_INSTRUCTIONS 
+                                     | llvm::MachO::S_ATTR_SOME_INSTRUCTIONS));
+  EXPECT_EQ(sect1.alignment, 1U);
+  EXPECT_EQ(sect1.address, 0x0ULL);
+  EXPECT_EQ(sect1.content.size(), 22UL);
+  EXPECT_EQ((int)(sect1.content[0]), 0x80);
+  EXPECT_EQ((int)(sect1.content[1]), 0xb5);
+  EXPECT_EQ(sect1.relocations.size(), 5UL);
+  const Relocation& reloc1 = sect1.relocations[0];
+  EXPECT_EQ(reloc1.offset, 0x0eU);
+  EXPECT_FALSE(reloc1.scattered);
+  EXPECT_EQ((int)reloc1.type, (int)llvm::MachO::ARM_THUMB_RELOC_BR22);
+  EXPECT_EQ(reloc1.length, 2);
+  EXPECT_TRUE(reloc1.pcRel);
+  EXPECT_TRUE(reloc1.isExtern);
+  EXPECT_EQ(reloc1.symbol, 1U);
+  EXPECT_EQ((int)(reloc1.value), 0);
+  const Relocation& reloc2 = sect1.relocations[1];
+  EXPECT_EQ(reloc2.offset, 0x8U);
+  EXPECT_TRUE(reloc2.scattered);
+  EXPECT_EQ((int)reloc2.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(reloc2.length, 3);
+  EXPECT_FALSE(reloc2.pcRel);
+  EXPECT_EQ(reloc2.symbol, 0U);
+  EXPECT_EQ((int)(reloc2.value), 0x16);
+  const Relocation& reloc3 = sect1.relocations[2];
+  EXPECT_EQ(reloc3.offset, 0x6U);
+  EXPECT_TRUE(reloc3.scattered);
+  EXPECT_EQ((int)reloc3.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc3.length, 3);
+  EXPECT_FALSE(reloc3.pcRel);
+  EXPECT_EQ(reloc3.symbol, 0U);
+  EXPECT_EQ((int)(reloc3.value), 0xc);
+   const Relocation& reloc4 = sect1.relocations[3];
+  EXPECT_EQ(reloc4.offset, 0x2U);
+  EXPECT_TRUE(reloc4.scattered);
+  EXPECT_EQ((int)reloc4.type, (int)llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
+  EXPECT_EQ(reloc4.length, 2);
+  EXPECT_FALSE(reloc4.pcRel);
+  EXPECT_EQ(reloc4.symbol, 0U);
+  EXPECT_EQ((int)(reloc4.value), 0x16);
+  const Relocation& reloc5 = sect1.relocations[4];
+  EXPECT_EQ(reloc5.offset, 0x0U);
+  EXPECT_TRUE(reloc5.scattered);
+  EXPECT_EQ((int)reloc5.type, (int)llvm::MachO::ARM_RELOC_PAIR);
+  EXPECT_EQ(reloc5.length, 2);
+  EXPECT_FALSE(reloc5.pcRel);
+  EXPECT_EQ(reloc5.symbol, 0U);
+  EXPECT_EQ((int)(reloc5.value), 0xc);
+
+  const Section& sect2 = f->sections[1];
+  EXPECT_TRUE(sect2.segmentName.equals("__TEXT"));
+  EXPECT_TRUE(sect2.sectionName.equals("__cstring"));
+  EXPECT_EQ((uint32_t)(sect2.type), (uint32_t)(llvm::MachO::S_CSTRING_LITERALS));
+  EXPECT_EQ((uint32_t)(sect2.attributes), 0U);
+  EXPECT_EQ(sect2.alignment, 0U);
+  EXPECT_EQ(sect2.address, 0x016ULL);
+  EXPECT_EQ(sect2.content.size(), 7UL);
+  EXPECT_EQ((int)(sect2.content[0]), 0x68);
+  EXPECT_EQ((int)(sect2.content[1]), 0x65);
+  EXPECT_EQ((int)(sect2.content[2]), 0x6c);
+  
+  EXPECT_EQ(f->globalSymbols.size(), 1UL);
+  const Symbol& sym1 = f->globalSymbols[0];
+  EXPECT_TRUE(sym1.name.equals("_main"));
+  EXPECT_EQ((int)(sym1.type), llvm::MachO::N_SECT);
+  EXPECT_EQ((int)(sym1.scope), llvm::MachO::N_EXT);
+  EXPECT_EQ(sym1.sect, 1);
+  EXPECT_EQ((int)(sym1.desc), (int)(llvm::MachO::N_ARM_THUMB_DEF));
+  EXPECT_EQ((uint64_t)sym1.value, 0x0ULL);
+  EXPECT_EQ(f->undefinedSymbols.size(), 1UL);
+  const Symbol& sym2 = f->undefinedSymbols[0];
+  EXPECT_TRUE(sym2.name.equals("_printf"));
+  EXPECT_EQ((int)(sym2.type), llvm::MachO::N_UNDF);
+  EXPECT_EQ((int)(sym2.scope), 0);
+  EXPECT_EQ(sym2.sect, 0);
+  EXPECT_EQ((int)(sym2.desc), 0);
+  EXPECT_EQ((uint64_t)sym2.value, 0x0ULL);
+}





More information about the llvm-commits mailing list