2013-10-08 08:43:34 +08:00
|
|
|
//===- 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"
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
#include "lld/ReaderWriter/YamlContext.h"
|
2013-10-08 08:43:34 +08:00
|
|
|
|
|
|
|
#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;
|
2013-11-07 05:36:55 +08:00
|
|
|
using namespace llvm::yaml;
|
|
|
|
using namespace llvm::MachO;
|
|
|
|
using namespace lld::mach_o::normalized;
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
using lld::YamlContext;
|
2013-10-15 05:24:48 +08:00
|
|
|
|
2013-12-28 08:46:57 +08:00
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
|
|
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
|
2013-10-15 05:24:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
|
|
|
|
namespace llvm {
|
|
|
|
namespace yaml {
|
|
|
|
|
2013-10-08 08:43:34 +08:00
|
|
|
// 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);
|
2014-01-04 09:22:05 +08:00
|
|
|
io.enumCase(value, "N_PBUD", llvm::MachO::N_PBUD);
|
|
|
|
io.enumCase(value, "N_INDR", llvm::MachO::N_INDR);
|
2013-10-08 08:43:34 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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> {
|
2014-01-04 07:12:02 +08:00
|
|
|
struct NormalizedContentBytes;
|
2013-10-08 08:43:34 +08:00
|
|
|
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);
|
2014-01-04 07:12:02 +08:00
|
|
|
MappingNormalization<NormalizedContent, std::vector<uint8_t>> content(
|
|
|
|
io, sect.content);
|
|
|
|
io.mapOptional("content", content->normalizedContent);
|
2013-10-08 08:43:34 +08:00
|
|
|
io.mapOptional("relocations", sect.relocations);
|
|
|
|
io.mapOptional("indirect-syms", sect.indirectSymbols);
|
|
|
|
}
|
2014-01-04 07:12:02 +08:00
|
|
|
|
|
|
|
// FIXME: It would be good if we could remove this, so we don't need to copy
|
|
|
|
// the content data.
|
|
|
|
struct NormalizedContent {
|
|
|
|
NormalizedContent(IO &) {}
|
|
|
|
NormalizedContent(IO &, std::vector<uint8_t> content) {
|
|
|
|
for (auto &c : content) {
|
|
|
|
normalizedContent.push_back(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::vector<uint8_t> denormalize(IO &) {
|
|
|
|
std::vector<uint8_t> content;
|
|
|
|
for (auto &c : normalizedContent) {
|
|
|
|
content.push_back(c);
|
|
|
|
}
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
ContentBytes normalizedContent;
|
|
|
|
};
|
2013-10-08 08:43:34 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
2013-12-20 15:48:29 +08:00
|
|
|
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
assert(info != nullptr);
|
|
|
|
NormalizedFile *file = info->_normalizeMachOFile;
|
2013-10-08 08:43:34 +08:00
|
|
|
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:
|
2013-10-08 10:07:19 +08:00
|
|
|
llvm_unreachable("unknown architecture");
|
2013-10-08 08:43:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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> {
|
2013-11-05 09:37:40 +08:00
|
|
|
static void output(const VMProtect &value, void*, raw_ostream &out) {
|
2013-10-08 08:43:34 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-10-15 05:24:48 +08:00
|
|
|
|
2013-10-08 08:43:34 +08:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
static StringRef validate(IO &io, NormalizedFile &file) {
|
|
|
|
return StringRef();
|
|
|
|
}
|
2013-10-08 08:43:34 +08:00
|
|
|
};
|
|
|
|
|
2013-10-15 05:24:48 +08:00
|
|
|
} // namespace llvm
|
|
|
|
} // namespace yaml
|
|
|
|
|
2013-10-08 08:43:34 +08:00
|
|
|
|
|
|
|
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.
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
YamlContext yamlContext;
|
|
|
|
yamlContext._normalizeMachOFile = f.get();
|
|
|
|
llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
|
2013-10-08 08:43:34 +08:00
|
|
|
|
|
|
|
// Fill NormalizedFile by parsing yaml.
|
|
|
|
yin >> *f;
|
|
|
|
|
|
|
|
// Return error if there were parsing problems.
|
|
|
|
if (yin.error())
|
2013-10-09 08:57:22 +08:00
|
|
|
return make_error_code(lld::YamlReaderError::illegal_value);
|
2013-10-08 08:43:34 +08:00
|
|
|
|
|
|
|
// 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
|
2013-11-05 09:37:40 +08:00
|
|
|
writeYaml(const NormalizedFile &file, raw_ostream &out) {
|
2013-10-08 08:43:34 +08:00
|
|
|
// 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.
|
[lld] Introduce registry and Reference kind tuple
The main changes are in:
include/lld/Core/Reference.h
include/lld/ReaderWriter/Reader.h
Everything else is details to support the main change.
1) Registration based Readers
Previously, lld had a tangled interdependency with all the Readers. It would
have been impossible to make a streamlined linker (say for a JIT) which
just supported one file format and one architecture (no yaml, no archives, etc).
The old model also required a LinkingContext to read an object file, which
would have made .o inspection tools awkward.
The new model is that there is a global Registry object. You programmatically
register the Readers you want with the registry object. Whenever you need to
read/parse a file, you ask the registry to do it, and the registry tries each
registered reader.
For ease of use with the existing lld code base, there is one Registry
object inside the LinkingContext object.
2) Changing kind value to be a tuple
Beside Readers, the registry also keeps track of the mapping for Reference
Kind values to and from strings. Along with that, this patch also fixes
an ambiguity with the previous Reference::Kind values. The problem was that
we wanted to reuse existing relocation type values as Reference::Kind values.
But then how can the YAML write know how to convert a value to a string? The
fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace
(e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and
a 16-bit value. This tuple system allows conversion to and from strings with
no ambiguities.
llvm-svn: 197727
2013-12-20 05:58:00 +08:00
|
|
|
YamlContext yamlContext;
|
|
|
|
yamlContext._normalizeMachOFile = f;
|
|
|
|
llvm::yaml::Output yout(out, &yamlContext);
|
2013-10-08 08:43:34 +08:00
|
|
|
|
|
|
|
// Stream out yaml.
|
|
|
|
yout << *f;
|
|
|
|
|
|
|
|
return error_code::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace normalized
|
|
|
|
} // namespace mach_o
|
|
|
|
} // namespace lld
|
|
|
|
|