From 30332b19d3a305536d66dac5c9c8d58a8f8a6419 Mon Sep 17 00:00:00 2001 From: Nick Kledzik Date: Tue, 8 Oct 2013 00:43:34 +0000 Subject: [PATCH] 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. llvm-svn: 192147 --- lld/include/lld/ReaderWriter/MachOLinkingContext.h | 3 +- lld/lib/ReaderWriter/MachO/CMakeLists.txt | 1 + lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp | 11 +- lld/lib/ReaderWriter/MachO/MachONormalizedFile.h | 279 ++++++++ .../ReaderWriter/MachO/MachONormalizedFileYAML.cpp | 650 +++++++++++++++++ lld/unittests/CMakeLists.txt | 1 + lld/unittests/MachOTests/CMakeLists.txt | 9 + .../MachOTests/MachONormalizedFileYAMLTests.cpp | 769 +++++++++++++++++++++ 8 files changed, 1716 insertions(+), 7 deletions(-) create mode 100644 lld/lib/ReaderWriter/MachO/MachONormalizedFile.h create mode 100644 lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp create mode 100644 lld/unittests/MachOTests/CMakeLists.txt create mode 100644 lld/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index fc5de2f..c214ba7 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -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; } diff --git a/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/lld/lib/ReaderWriter/MachO/CMakeLists.txt index 899c3ff..353ffbd 100644 --- a/lld/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lld/lib/ReaderWriter/MachO/CMakeLists.txt @@ -1,5 +1,6 @@ add_lld_library(lldMachO MachOLinkingContext.cpp + MachONormalizedFileYAML.cpp ReferenceKinds.cpp WriterMachO.cpp ) diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 11f5a48..69219e5 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -149,20 +149,19 @@ bool MachOLinkingContext::outputTypeHasEntry() const { } 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"); } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h new file mode 100644 index 0000000..37206dd --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -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 Relocations; + +/// A typedef so that YAML I/O can process the raw bytes in a section. +typedef std::vector ContentBytes; + +/// A typedef so that YAML I/O can treat indirect symbols as a flow sequence. +typedef std::vector 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 segments; // Not used in object files. + std::vector
sections; + + // Symbols sorted by kind. + std::vector localSymbols; + std::vector globalSymbols; + std::vector undefinedSymbols; + + // Maps to load commands with no LINKEDIT content (final linked images only). + std::vector dependentDylibs; + StringRef installName; + bool hasUUID; + std::vector 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 rebasingInfo; + std::vector bindingInfo; + std::vector weakBindingInfo; + std::vector lazyBindingInfo; + std::vector 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> +readBinary(std::unique_ptr &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> +readYaml(std::unique_ptr &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> +normalizedToAtoms(const NormalizedFile &normalizedFile); + +/// Takes atoms and generates a normalized macho-o view. +ErrorOr> +normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt); + + + +} // namespace normalized +} // namespace mach_o +} // namespace lld + +#endif // LLD_READER_WRITER_MACHO_NORMALIZED_H_ + + + + diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp new file mode 100644 index 0000000..1e212d8 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -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
> { + static size_t size(IO &io, std::vector
&seq) { + return seq.size(); + } + static Section& element(IO &io, std::vector
&seq, size_t index) { + if ( index >= seq.size() ) + seq.resize(index+1); + return seq[index]; + } +}; + +template<> +struct SequenceTraits< std::vector > { + static size_t size(IO &io, std::vector &seq) { + return seq.size(); + } + static Symbol& element(IO &io, std::vector &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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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
{ + static void mapping(IO &io, Section §) { + 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 { + 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 { + static void enumeration(IO &io, RelocationInfoType &value) { + NormalizedFile *file = reinterpret_cast(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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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> +readYaml(std::unique_ptr &mb) { + // Make empty NormalizedFile. + std::unique_ptr 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(&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 + diff --git a/lld/unittests/CMakeLists.txt b/lld/unittests/CMakeLists.txt index 53b699f..bb651b5 100644 --- a/lld/unittests/CMakeLists.txt +++ b/lld/unittests/CMakeLists.txt @@ -12,3 +12,4 @@ endfunction() add_subdirectory(CoreTests) add_subdirectory(DriverTests) +add_subdirectory(MachOTests) diff --git a/lld/unittests/MachOTests/CMakeLists.txt b/lld/unittests/MachOTests/CMakeLists.txt new file mode 100644 index 0000000..e0748eb --- /dev/null +++ b/lld/unittests/MachOTests/CMakeLists.txt @@ -0,0 +1,9 @@ + +add_lld_unittest(lldMachOTests + MachONormalizedFileYAMLTests.cpp + ) + +target_link_libraries(lldMachOTests + lldMachO + lldYAML + ) diff --git a/lld/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp b/lld/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp new file mode 100644 index 0000000..50eafee --- /dev/null +++ b/lld/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp @@ -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 +#include + +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 fromYAML(StringRef str) { + std::unique_ptr mb(MemoryBuffer::getMemBuffer(str)); + ErrorOr> 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 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 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 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 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 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 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 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 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 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 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 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 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 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); +} -- 2.7.4