llvm-project/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp

1403 lines
54 KiB
C++
Raw Normal View History

//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/Error.h"
#include "lld/Core/File.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Reader.h"
#include "lld/Core/Reference.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/Simple.h"
#include "lld/Core/UndefinedAtom.h"
#include "lld/Core/Writer.h"
#include "lld/ReaderWriter/YamlContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
using llvm::yaml::MappingTraits;
using llvm::yaml::ScalarEnumerationTraits;
using llvm::yaml::ScalarTraits;
using llvm::yaml::IO;
using llvm::yaml::SequenceTraits;
using llvm::yaml::DocumentListTraits;
using namespace lld;
/// The conversion of Atoms to and from YAML uses LLVM's YAML I/O. This
/// file just defines template specializations on the lld types which control
/// how the mapping is done to and from YAML.
namespace {
/// Used when writing yaml files.
/// In most cases, atoms names are unambiguous, so references can just
/// use the atom name as the target (e.g. target: foo). But in a few
/// cases that does not work, so ref-names are added. These are labels
/// used only in yaml. The labels do not exist in the Atom model.
///
/// One need for ref-names are when atoms have no user supplied name
/// (e.g. c-string literal). Another case is when two object files with
/// identically named static functions are merged (ld -r) into one object file.
/// In that case referencing the function by name is ambiguous, so a unique
/// ref-name is added.
class RefNameBuilder {
public:
RefNameBuilder(const lld::File &file)
2013-09-12 06:21:42 +08:00
: _collisionCount(0), _unnamedCounter(0) {
// visit all atoms
for (const lld::DefinedAtom *atom : file.defined()) {
// Build map of atoms names to detect duplicates
if (!atom->name().empty())
buildDuplicateNameMap(*atom);
// Find references to unnamed atoms and create ref-names for them.
for (const lld::Reference *ref : *atom) {
// create refname for any unnamed reference target
const lld::Atom *target = ref->target();
if ((target != nullptr) && target->name().empty()) {
std::string storage;
llvm::raw_string_ostream buffer(storage);
buffer << llvm::format("L%03d", _unnamedCounter++);
StringRef newName = copyString(buffer.str());
_refNames[target] = newName;
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "unnamed atom: creating ref-name: '"
<< newName << "' ("
<< (const void *)newName.data() << ", "
2013-09-12 06:21:42 +08:00
<< newName.size() << ")\n");
}
}
}
for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
buildDuplicateNameMap(*undefAtom);
}
for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
buildDuplicateNameMap(*shlibAtom);
}
for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
if (!absAtom->name().empty())
buildDuplicateNameMap(*absAtom);
}
}
void buildDuplicateNameMap(const lld::Atom &atom) {
assert(!atom.name().empty());
NameToAtom::iterator pos = _nameMap.find(atom.name());
2013-09-12 06:21:42 +08:00
if (pos != _nameMap.end()) {
// Found name collision, give each a unique ref-name.
std::string Storage;
llvm::raw_string_ostream buffer(Storage);
buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
StringRef newName = copyString(buffer.str());
_refNames[&atom] = newName;
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "name collsion: creating ref-name: '"
<< newName << "' ("
<< (const void *)newName.data()
2013-09-12 06:21:42 +08:00
<< ", " << newName.size() << ")\n");
const lld::Atom *prevAtom = pos->second;
AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
2013-09-12 06:21:42 +08:00
if (pos2 == _refNames.end()) {
// Only create ref-name for previous if none already created.
std::string Storage2;
llvm::raw_string_ostream buffer2(Storage2);
buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
StringRef newName2 = copyString(buffer2.str());
_refNames[prevAtom] = newName2;
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "name collsion: creating ref-name: '"
<< newName2 << "' ("
<< (const void *)newName2.data() << ", "
2013-09-12 06:21:42 +08:00
<< newName2.size() << ")\n");
}
2013-09-12 06:21:42 +08:00
} else {
// First time we've seen this name, just add it to map.
_nameMap[atom.name()] = &atom;
DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
2013-09-12 06:21:42 +08:00
<< "atom name seen for first time: '"
<< atom.name() << "' ("
<< (const void *)atom.name().data()
<< ", " << atom.name().size() << ")\n");
}
}
2013-09-12 06:21:42 +08:00
bool hasRefName(const lld::Atom *atom) { return _refNames.count(atom); }
StringRef refName(const lld::Atom *atom) {
2013-09-12 06:21:42 +08:00
return _refNames.find(atom)->second;
}
private:
2013-09-12 06:21:42 +08:00
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
typedef llvm::DenseMap<const lld::Atom *, std::string> AtomToRefName;
// Allocate a new copy of this string in _storage, so the strings
// can be freed when RefNameBuilder is destroyed.
StringRef copyString(StringRef str) {
2014-01-13 12:08:15 +08:00
char *s = _storage.Allocate<char>(str.size());
memcpy(s, str.data(), str.size());
return StringRef(s, str.size());
}
unsigned int _collisionCount;
unsigned int _unnamedCounter;
NameToAtom _nameMap;
AtomToRefName _refNames;
llvm::BumpPtrAllocator _storage;
};
/// Used when reading yaml files to find the target of a reference
/// that could be a name or ref-name.
class RefNameResolver {
public:
RefNameResolver(const lld::File *file, IO &io);
const lld::Atom *lookup(StringRef name) const {
NameToAtom::const_iterator pos = _nameMap.find(name);
if (pos != _nameMap.end())
return pos->second;
_io.setError(Twine("no such atom name: ") + name);
return nullptr;
}
private:
2013-09-12 06:21:42 +08:00
typedef llvm::StringMap<const lld::Atom *> NameToAtom;
void add(StringRef name, const lld::Atom *atom) {
if (_nameMap.count(name)) {
_io.setError(Twine("duplicate atom name: ") + name);
2013-09-12 06:21:42 +08:00
} else {
_nameMap[name] = atom;
}
}
2013-09-12 06:21:42 +08:00
IO &_io;
NameToAtom _nameMap;
};
/// Mapping of Atoms.
template <typename T> class AtomList {
using Ty = std::vector<OwningAtomPtr<T>>;
public:
typename Ty::iterator begin() { return _atoms.begin(); }
typename Ty::iterator end() { return _atoms.end(); }
Ty _atoms;
};
/// Mapping of kind: field in yaml files.
enum FileKinds {
2013-09-12 06:21:42 +08:00
fileKindObjectAtoms, // atom based object file encoded in yaml
fileKindArchive, // static archive library encoded in yaml
fileKindObjectMachO // mach-o object files encoded in yaml
};
struct ArchMember {
FileKinds _kind;
StringRef _name;
const lld::File *_content;
};
// The content bytes in a DefinedAtom are just uint8_t but we want
// special formatting, so define a strong type.
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
// more readable than just true/false.
LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
[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
// lld::Reference::Kind is a tuple of <namespace, arch, value>.
// For yaml, we just want one string that encapsulates the tuple.
struct RefKind {
Reference::KindNamespace ns;
Reference::KindArch arch;
Reference::KindValue value;
[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
};
} // end anonymous namespace
2013-01-25 15:39:18 +08:00
LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember)
2013-09-12 06:21:42 +08:00
LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference *)
// Always write DefinedAtoms content bytes as a flow sequence.
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8)
2013-09-12 06:21:42 +08:00
// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
namespace llvm {
namespace yaml {
// This is a custom formatter for RefKind
2013-09-12 06:21:42 +08:00
template <> struct ScalarTraits<RefKind> {
[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 void output(const RefKind &kind, void *ctxt, raw_ostream &out) {
assert(ctxt != nullptr);
[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 *info = reinterpret_cast<YamlContext *>(ctxt);
assert(info->_registry);
StringRef str;
if (info->_registry->referenceKindToString(kind.ns, kind.arch, kind.value,
str))
[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
out << str;
else
out << (int)(kind.ns) << "-" << (int)(kind.arch) << "-" << kind.value;
}
[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 input(StringRef scalar, void *ctxt, RefKind &kind) {
assert(ctxt != nullptr);
[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 *info = reinterpret_cast<YamlContext *>(ctxt);
assert(info->_registry);
if (info->_registry->referenceKindFromString(scalar, kind.ns, kind.arch,
kind.value))
[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
return StringRef();
return StringRef("unknown reference kind");
}
static bool mustQuote(StringRef) { return false; }
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::File::Kind> {
static void enumeration(IO &io, lld::File::Kind &value) {
io.enumCase(value, "error-object", lld::File::kindErrorObject);
io.enumCase(value, "object", lld::File::kindMachObject);
io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::Atom::Scope> {
static void enumeration(IO &io, lld::Atom::Scope &value) {
io.enumCase(value, "global", lld::Atom::scopeGlobal);
io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
io.enumCase(value, "custom-required",
lld::DefinedAtom::sectionCustomRequired);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
io.enumCase(value, "no", DefinedAtom::interposeNo);
io.enumCase(value, "yes", DefinedAtom::interposeYes);
io.enumCase(value, "yes-and-weak", DefinedAtom::interposeYesAndRuntimeWeak);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
io.enumCase(value, "as-addressed-weak",
lld::DefinedAtom::mergeAsWeakAndAddressUsed);
io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
io.enumCase(value, "same-name-and-size",
lld::DefinedAtom::mergeSameNameAndSize);
io.enumCase(value, "largest", lld::DefinedAtom::mergeByLargestSection);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
}
};
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::DynamicExport> {
static void enumeration(IO &io, lld::DefinedAtom::DynamicExport &value) {
io.enumCase(value, "normal", lld::DefinedAtom::dynamicExportNormal);
io.enumCase(value, "always", lld::DefinedAtom::dynamicExportAlways);
}
};
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::CodeModel> {
static void enumeration(IO &io, lld::DefinedAtom::CodeModel &value) {
io.enumCase(value, "none", lld::DefinedAtom::codeNA);
io.enumCase(value, "mips-pic", lld::DefinedAtom::codeMipsPIC);
io.enumCase(value, "mips-micro", lld::DefinedAtom::codeMipsMicro);
io.enumCase(value, "mips-micro-pic", lld::DefinedAtom::codeMipsMicroPIC);
io.enumCase(value, "mips-16", lld::DefinedAtom::codeMips16);
io.enumCase(value, "arm-thumb", lld::DefinedAtom::codeARMThumb);
io.enumCase(value, "arm-a", lld::DefinedAtom::codeARM_a);
io.enumCase(value, "arm-d", lld::DefinedAtom::codeARM_d);
io.enumCase(value, "arm-t", lld::DefinedAtom::codeARM_t);
}
};
template <>
struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
io.enumCase(value, "---", lld::DefinedAtom::perm___);
io.enumCase(value, "r--", lld::DefinedAtom::permR__);
io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
io.enumCase(value, "unknown", DefinedAtom::typeUnknown);
io.enumCase(value, "code", DefinedAtom::typeCode);
io.enumCase(value, "stub", DefinedAtom::typeStub);
io.enumCase(value, "constant", DefinedAtom::typeConstant);
io.enumCase(value, "data", DefinedAtom::typeData);
io.enumCase(value, "quick-data", DefinedAtom::typeDataFast);
io.enumCase(value, "zero-fill", DefinedAtom::typeZeroFill);
io.enumCase(value, "zero-fill-quick", DefinedAtom::typeZeroFillFast);
io.enumCase(value, "const-data", DefinedAtom::typeConstData);
io.enumCase(value, "got", DefinedAtom::typeGOT);
io.enumCase(value, "resolver", DefinedAtom::typeResolver);
io.enumCase(value, "branch-island", DefinedAtom::typeBranchIsland);
io.enumCase(value, "branch-shim", DefinedAtom::typeBranchShim);
io.enumCase(value, "stub-helper", DefinedAtom::typeStubHelper);
io.enumCase(value, "c-string", DefinedAtom::typeCString);
io.enumCase(value, "utf16-string", DefinedAtom::typeUTF16String);
io.enumCase(value, "unwind-cfi", DefinedAtom::typeCFI);
io.enumCase(value, "unwind-lsda", DefinedAtom::typeLSDA);
io.enumCase(value, "const-4-byte", DefinedAtom::typeLiteral4);
io.enumCase(value, "const-8-byte", DefinedAtom::typeLiteral8);
io.enumCase(value, "const-16-byte", DefinedAtom::typeLiteral16);
io.enumCase(value, "lazy-pointer", DefinedAtom::typeLazyPointer);
io.enumCase(value, "lazy-dylib-pointer",
DefinedAtom::typeLazyDylibPointer);
io.enumCase(value, "cfstring", DefinedAtom::typeCFString);
io.enumCase(value, "initializer-pointer",
DefinedAtom::typeInitializerPtr);
io.enumCase(value, "terminator-pointer",
DefinedAtom::typeTerminatorPtr);
io.enumCase(value, "c-string-pointer",DefinedAtom::typeCStringPtr);
io.enumCase(value, "objc-class-pointer",
DefinedAtom::typeObjCClassPtr);
io.enumCase(value, "objc-category-list",
DefinedAtom::typeObjC2CategoryList);
io.enumCase(value, "objc-image-info",
DefinedAtom::typeObjCImageInfo);
io.enumCase(value, "objc-method-list",
DefinedAtom::typeObjCMethodList);
io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class);
io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF);
io.enumCase(value, "interposing-tuples",
DefinedAtom::typeInterposingTuples);
io.enumCase(value, "lto-temp", DefinedAtom::typeTempLTO);
io.enumCase(value, "compact-unwind", DefinedAtom::typeCompactUnwindInfo);
io.enumCase(value, "unwind-info", DefinedAtom::typeProcessedUnwindInfo);
io.enumCase(value, "tlv-thunk", DefinedAtom::typeThunkTLV);
io.enumCase(value, "tlv-data", DefinedAtom::typeTLVInitialData);
io.enumCase(value, "tlv-zero-fill", DefinedAtom::typeTLVInitialZeroFill);
io.enumCase(value, "tlv-initializer-ptr",
DefinedAtom::typeTLVInitializerPtr);
io.enumCase(value, "mach_header", DefinedAtom::typeMachHeader);
io.enumCase(value, "dso_handle", DefinedAtom::typeDSOHandle);
io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
io.enumCase(value, "at-buildtime",lld::UndefinedAtom::canBeNullAtBuildtime);
}
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<ShlibCanBeNull> {
static void enumeration(IO &io, ShlibCanBeNull &value) {
io.enumCase(value, "never", false);
2013-09-12 06:21:42 +08:00
io.enumCase(value, "at-runtime", true);
}
};
template <>
struct ScalarEnumerationTraits<lld::SharedLibraryAtom::Type> {
static void enumeration(IO &io, lld::SharedLibraryAtom::Type &value) {
io.enumCase(value, "code", lld::SharedLibraryAtom::Type::Code);
io.enumCase(value, "data", lld::SharedLibraryAtom::Type::Data);
io.enumCase(value, "unknown", lld::SharedLibraryAtom::Type::Unknown);
}
};
/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
/// like:
/// 8 # 8-byte aligned
/// 7 mod 16 # 16-byte aligned plus 7 bytes
2013-09-12 06:21:42 +08:00
template <> struct ScalarTraits<lld::DefinedAtom::Alignment> {
static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
raw_ostream &out) {
if (value.modulus == 0) {
out << llvm::format("%d", value.value);
2013-09-12 06:21:42 +08:00
} else {
out << llvm::format("%d mod %d", value.modulus, value.value);
}
}
static StringRef input(StringRef scalar, void *ctxt,
2013-09-12 06:21:42 +08:00
lld::DefinedAtom::Alignment &value) {
value.modulus = 0;
size_t modStart = scalar.find("mod");
if (modStart != StringRef::npos) {
StringRef modStr = scalar.slice(0, modStart);
modStr = modStr.rtrim();
unsigned int modulus;
if (modStr.getAsInteger(0, modulus)) {
return "malformed alignment modulus";
}
value.modulus = modulus;
2013-09-12 06:21:42 +08:00
scalar = scalar.drop_front(modStart + 3);
scalar = scalar.ltrim();
}
unsigned int power;
if (scalar.getAsInteger(0, power)) {
return "malformed alignment power";
}
value.value = power;
if (value.modulus >= power) {
return "malformed alignment, modulus too large for power";
}
return StringRef(); // returning empty string means success
}
static bool mustQuote(StringRef) { return false; }
};
2013-09-12 06:21:42 +08:00
template <> struct ScalarEnumerationTraits<FileKinds> {
static void enumeration(IO &io, FileKinds &value) {
io.enumCase(value, "object", fileKindObjectAtoms);
io.enumCase(value, "archive", fileKindArchive);
io.enumCase(value, "object-mach-o", fileKindObjectMachO);
}
};
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<ArchMember> {
static void mapping(IO &io, ArchMember &member) {
io.mapOptional("kind", member._kind, fileKindObjectAtoms);
io.mapOptional("name", member._name);
io.mapRequired("content", member._content);
}
};
// Declare that an AtomList is a yaml sequence.
2013-09-12 06:21:42 +08:00
template <typename T> struct SequenceTraits<AtomList<T> > {
static size_t size(IO &io, AtomList<T> &seq) { return seq._atoms.size(); }
static T *&element(IO &io, AtomList<T> &seq, size_t index) {
if (index >= seq._atoms.size())
2013-09-12 06:21:42 +08:00
seq._atoms.resize(index + 1);
return seq._atoms[index].get();
}
};
// Declare that an AtomRange is a yaml sequence.
template <typename T> struct SequenceTraits<File::AtomRange<T> > {
static size_t size(IO &io, File::AtomRange<T> &seq) { return seq.size(); }
static T *&element(IO &io, File::AtomRange<T> &seq, size_t index) {
assert(io.outputting() && "AtomRange only used when outputting");
assert(index < seq.size() && "Out of range access");
return seq[index].get();
}
};
// Used to allow DefinedAtom content bytes to be a flow sequence of
// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
2013-09-12 06:21:42 +08:00
template <> struct ScalarTraits<ImplicitHex8> {
static void output(const ImplicitHex8 &val, void *, raw_ostream &out) {
uint8_t num = val;
out << llvm::format("%02X", num);
}
static StringRef input(StringRef str, void *, ImplicitHex8 &val) {
unsigned long long n;
if (getAsUnsignedInteger(str, 16, n))
return "invalid two-digit-hex number";
if (n > 0xFF)
return "out of range two-digit-hex number";
val = n;
return StringRef(); // returning empty string means success
}
static bool mustQuote(StringRef) { return false; }
};
// YAML conversion for std::vector<const lld::File*>
2013-09-12 06:21:42 +08:00
template <> struct DocumentListTraits<std::vector<const lld::File *> > {
static size_t size(IO &io, std::vector<const lld::File *> &seq) {
return seq.size();
}
2013-09-12 06:21:42 +08:00
static const lld::File *&element(IO &io, std::vector<const lld::File *> &seq,
size_t index) {
if (index >= seq.size())
2013-09-12 06:21:42 +08:00
seq.resize(index + 1);
return seq[index];
}
};
// YAML conversion for const lld::File*
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<const lld::File *> {
class NormArchiveFile : public lld::ArchiveLibraryFile {
public:
NormArchiveFile(IO &io) : ArchiveLibraryFile("") {}
2013-09-12 06:21:42 +08:00
NormArchiveFile(IO &io, const lld::File *file)
[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
: ArchiveLibraryFile(file->path()), _path(file->path()) {
2013-09-12 06:21:42 +08:00
// If we want to support writing archives, this constructor would
// need to populate _members.
}
2013-09-12 06:21:42 +08:00
const lld::File *denormalize(IO &io) { return this; }
const AtomRange<lld::DefinedAtom> defined() const override {
return _noDefinedAtoms;
}
const AtomRange<lld::UndefinedAtom> undefined() const override {
return _noUndefinedAtoms;
}
const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
return _noSharedLibraryAtoms;
}
const AtomRange<lld::AbsoluteAtom> absolute() const override {
return _noAbsoluteAtoms;
}
void clearAtoms() override {
_noDefinedAtoms.clear();
_noUndefinedAtoms.clear();
_noSharedLibraryAtoms.clear();
_noAbsoluteAtoms.clear();
}
File *find(StringRef name) override {
for (const ArchMember &member : _members)
for (const lld::DefinedAtom *atom : member._content->defined())
if (name == atom->name())
return const_cast<File *>(member._content);
return nullptr;
}
std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
return std::error_code();
[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
}
StringRef _path;
2013-09-12 06:21:42 +08:00
std::vector<ArchMember> _members;
};
2013-01-25 15:39:18 +08:00
2013-09-12 06:21:42 +08:00
class NormalizedFile : public lld::File {
public:
NormalizedFile(IO &io)
: File("", kindNormalizedObject), _io(io), _rnb(nullptr),
_definedAtomsRef(_definedAtoms._atoms),
_undefinedAtomsRef(_undefinedAtoms._atoms),
_sharedLibraryAtomsRef(_sharedLibraryAtoms._atoms),
_absoluteAtomsRef(_absoluteAtoms._atoms) {}
2013-09-12 06:21:42 +08:00
NormalizedFile(IO &io, const lld::File *file)
: File(file->path(), kindNormalizedObject), _io(io),
_rnb(new RefNameBuilder(*file)), _path(file->path()),
_definedAtomsRef(file->defined()),
_undefinedAtomsRef(file->undefined()),
_sharedLibraryAtomsRef(file->sharedLibrary()),
_absoluteAtomsRef(file->absolute()) {
}
~NormalizedFile() override {
}
const lld::File *denormalize(IO &io);
const AtomRange<lld::DefinedAtom> defined() const override {
return _definedAtomsRef;
}
const AtomRange<lld::UndefinedAtom> undefined() const override {
return _undefinedAtomsRef;
}
const AtomRange<lld::SharedLibraryAtom> sharedLibrary() const override {
return _sharedLibraryAtomsRef;
}
const AtomRange<lld::AbsoluteAtom> absolute() const override {
return _absoluteAtomsRef;
}
void clearAtoms() override {
_definedAtoms._atoms.clear();
_undefinedAtoms._atoms.clear();
_sharedLibraryAtoms._atoms.clear();
_absoluteAtoms._atoms.clear();
2013-09-12 06:21:42 +08:00
}
2013-01-25 15:39:18 +08:00
// Allocate a new copy of this string in _storage, so the strings
// can be freed when File is destroyed.
StringRef copyString(StringRef str) {
2014-01-13 12:08:15 +08:00
char *s = _storage.Allocate<char>(str.size());
memcpy(s, str.data(), str.size());
return StringRef(s, str.size());
2013-09-12 06:21:42 +08:00
}
2013-01-25 15:39:18 +08:00
IO &_io;
std::unique_ptr<RefNameBuilder> _rnb;
StringRef _path;
AtomList<lld::DefinedAtom> _definedAtoms;
AtomList<lld::UndefinedAtom> _undefinedAtoms;
AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
AtomList<lld::AbsoluteAtom> _absoluteAtoms;
AtomRange<lld::DefinedAtom> _definedAtomsRef;
AtomRange<lld::UndefinedAtom> _undefinedAtomsRef;
AtomRange<lld::SharedLibraryAtom> _sharedLibraryAtomsRef;
AtomRange<lld::AbsoluteAtom> _absoluteAtomsRef;
llvm::BumpPtrAllocator _storage;
};
static void mapping(IO &io, const lld::File *&file) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
// Let any register tag handler process this.
if (info->_registry && info->_registry->handleTaggedDoc(io, file))
return;
// If no registered handler claims this tag and there is no tag,
// grandfather in as "!native".
if (io.mapTag("!native", true) || io.mapTag("tag:yaml.org,2002:map"))
2013-09-12 06:21:42 +08:00
mappingAtoms(io, file);
}
static void mappingAtoms(IO &io, const lld::File *&file) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormalizedFile, const lld::File *>
keys(io, file, nullptr);
assert(info != nullptr);
[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
info->_file = keys.operator->();
io.mapOptional("path", keys->_path);
if (io.outputting()) {
io.mapOptional("defined-atoms", keys->_definedAtomsRef);
io.mapOptional("undefined-atoms", keys->_undefinedAtomsRef);
io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtomsRef);
io.mapOptional("absolute-atoms", keys->_absoluteAtomsRef);
} else {
io.mapOptional("defined-atoms", keys->_definedAtoms);
io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
}
}
static void mappingArchive(IO &io, const lld::File *&file) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
MappingNormalizationHeap<NormArchiveFile, const lld::File *>
keys(io, file, &info->_file->allocator());
io.mapOptional("path", keys->_path);
2013-09-12 06:21:42 +08:00
io.mapOptional("members", keys->_members);
}
};
// YAML conversion for const lld::Reference*
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<const lld::Reference *> {
class NormalizedReference : public lld::Reference {
public:
NormalizedReference(IO &io)
: lld::Reference(lld::Reference::KindNamespace::all,
[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
lld::Reference::KindArch::all, 0),
_target(nullptr), _offset(0), _addend(0), _tag(0) {}
NormalizedReference(IO &io, const lld::Reference *ref)
: lld::Reference(ref->kindNamespace(), ref->kindArch(),
ref->kindValue()),
[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
_target(nullptr), _targetName(targetName(io, ref)),
2015-03-24 17:57:05 +08:00
_offset(ref->offsetInAtom()), _addend(ref->addend()),
_tag(ref->tag()) {
[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
_mappedKind.ns = ref->kindNamespace();
_mappedKind.arch = ref->kindArch();
_mappedKind.value = ref->kindValue();
}
const lld::Reference *denormalize(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
if (!_targetName.empty())
_targetName = f->copyString(_targetName);
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
<< "created Reference to name: '"
<< _targetName << "' ("
<< (const void *)_targetName.data()
<< ", " << _targetName.size() << ")\n");
[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
setKindNamespace(_mappedKind.ns);
setKindArch(_mappedKind.arch);
setKindValue(_mappedKind.value);
return this;
}
2013-09-12 06:21:42 +08:00
void bind(const RefNameResolver &);
static StringRef targetName(IO &io, const lld::Reference *ref);
uint64_t offsetInAtom() const override { return _offset; }
const lld::Atom *target() const override { return _target; }
Addend addend() const override { return _addend; }
void setAddend(Addend a) override { _addend = a; }
void setTarget(const lld::Atom *a) override { _target = a; }
2013-09-12 06:21:42 +08:00
const lld::Atom *_target;
StringRef _targetName;
uint32_t _offset;
Addend _addend;
RefKind _mappedKind;
2015-03-24 17:57:05 +08:00
uint32_t _tag;
};
static void mapping(IO &io, const lld::Reference *&ref) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
2013-09-12 06:21:42 +08:00
MappingNormalizationHeap<NormalizedReference, const lld::Reference *> keys(
io, ref, &info->_file->allocator());
io.mapRequired("kind", keys->_mappedKind);
2013-09-12 06:21:42 +08:00
io.mapOptional("offset", keys->_offset);
io.mapOptional("target", keys->_targetName);
io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
2015-03-24 17:57:05 +08:00
io.mapOptional("tag", keys->_tag, 0u);
}
};
// YAML conversion for const lld::DefinedAtom*
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<const lld::DefinedAtom *> {
class NormalizedAtom : public lld::DefinedAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _contentType(), _alignment(1) {
static uint32_t ordinalCounter = 1;
_ordinal = ordinalCounter++;
}
NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
: _file(fileFromContext(io)), _name(atom->name()),
2013-09-12 06:21:42 +08:00
_scope(atom->scope()), _interpose(atom->interposable()),
_merge(atom->merge()), _contentType(atom->contentType()),
_alignment(atom->alignment()), _sectionChoice(atom->sectionChoice()),
_deadStrip(atom->deadStrip()), _dynamicExport(atom->dynamicExport()),
_codeModel(atom->codeModel()),
_permissions(atom->permissions()), _size(atom->size()),
_sectionName(atom->customSectionName()),
_sectionSize(atom->sectionSize()) {
for (const lld::Reference *r : *atom)
2013-09-12 06:21:42 +08:00
_references.push_back(r);
if (!atom->occupiesDiskSpace())
return;
ArrayRef<uint8_t> cont = atom->rawContent();
_content.reserve(cont.size());
for (uint8_t x : cont)
_content.push_back(x);
}
~NormalizedAtom() override = default;
const lld::DefinedAtom *denormalize(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
2013-09-12 06:21:42 +08:00
if (!_name.empty())
_name = f->copyString(_name);
2013-09-12 06:21:42 +08:00
if (!_refName.empty())
_refName = f->copyString(_refName);
2013-09-12 06:21:42 +08:00
if (!_sectionName.empty())
_sectionName = f->copyString(_sectionName);
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created DefinedAtom named: '" << _name
<< "' (" << (const void *)_name.data()
<< ", " << _name.size() << ")\n");
return this;
}
2013-09-12 06:21:42 +08:00
void bind(const RefNameResolver &);
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
[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->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
uint64_t size() const override { return _size; }
Scope scope() const override { return _scope; }
Interposable interposable() const override { return _interpose; }
Merge merge() const override { return _merge; }
ContentType contentType() const override { return _contentType; }
Alignment alignment() const override { return _alignment; }
SectionChoice sectionChoice() const override { return _sectionChoice; }
StringRef customSectionName() const override { return _sectionName; }
uint64_t sectionSize() const override { return _sectionSize; }
DeadStripKind deadStrip() const override { return _deadStrip; }
DynamicExport dynamicExport() const override { return _dynamicExport; }
CodeModel codeModel() const override { return _codeModel; }
ContentPermissions permissions() const override { return _permissions; }
ArrayRef<uint8_t> rawContent() const override {
if (!occupiesDiskSpace())
return ArrayRef<uint8_t>();
return ArrayRef<uint8_t>(
reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
}
uint64_t ordinal() const override { return _ordinal; }
reference_iterator begin() const override {
uintptr_t index = 0;
2013-09-12 06:21:42 +08:00
const void *it = reinterpret_cast<const void *>(index);
return reference_iterator(*this, it);
}
reference_iterator end() const override {
uintptr_t index = _references.size();
2013-09-12 06:21:42 +08:00
const void *it = reinterpret_cast<const void *>(index);
return reference_iterator(*this, it);
}
const lld::Reference *derefIterator(const void *it) const override {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
assert(index < _references.size());
return _references[index];
}
void incrementIterator(const void *&it) const override {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
++index;
2013-09-12 06:21:42 +08:00
it = reinterpret_cast<const void *>(index);
}
void addReference(Reference::KindNamespace ns,
Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t off,
const Atom *target, Reference::Addend a) override {
assert(target && "trying to create reference to nothing");
auto node = new (file().allocator()) SimpleReference(ns, arch, kindValue,
off, target, a);
_references.push_back(node);
}
const lld::File &_file;
StringRef _name;
StringRef _refName;
Scope _scope;
Interposable _interpose;
Merge _merge;
ContentType _contentType;
Alignment _alignment;
SectionChoice _sectionChoice;
DeadStripKind _deadStrip;
DynamicExport _dynamicExport;
CodeModel _codeModel;
ContentPermissions _permissions;
uint32_t _ordinal;
std::vector<ImplicitHex8> _content;
uint64_t _size;
StringRef _sectionName;
uint64_t _sectionSize;
2013-09-12 06:21:42 +08:00
std::vector<const lld::Reference *> _references;
};
static void mapping(IO &io, const lld::DefinedAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
2013-09-12 06:21:42 +08:00
MappingNormalizationHeap<NormalizedAtom, const lld::DefinedAtom *> keys(
io, atom, &info->_file->allocator());
2013-09-12 06:21:42 +08:00
if (io.outputting()) {
// If writing YAML, check if atom needs a ref-name.
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
assert(info != nullptr);
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
assert(f);
assert(f->_rnb);
2013-09-12 06:21:42 +08:00
if (f->_rnb->hasRefName(atom)) {
keys->_refName = f->_rnb->refName(atom);
}
}
io.mapOptional("name", keys->_name, StringRef());
io.mapOptional("ref-name", keys->_refName, StringRef());
io.mapOptional("scope", keys->_scope,
DefinedAtom::scopeTranslationUnit);
io.mapOptional("type", keys->_contentType,
DefinedAtom::typeCode);
io.mapOptional("content", keys->_content);
io.mapOptional("size", keys->_size, (uint64_t)keys->_content.size());
io.mapOptional("interposable", keys->_interpose,
DefinedAtom::interposeNo);
io.mapOptional("merge", keys->_merge, DefinedAtom::mergeNo);
io.mapOptional("alignment", keys->_alignment,
DefinedAtom::Alignment(1));
io.mapOptional("section-choice", keys->_sectionChoice,
DefinedAtom::sectionBasedOnContent);
io.mapOptional("section-name", keys->_sectionName, StringRef());
io.mapOptional("section-size", keys->_sectionSize, (uint64_t)0);
io.mapOptional("dead-strip", keys->_deadStrip,
DefinedAtom::deadStripNormal);
io.mapOptional("dynamic-export", keys->_dynamicExport,
DefinedAtom::dynamicExportNormal);
io.mapOptional("code-model", keys->_codeModel, DefinedAtom::codeNA);
// default permissions based on content type
io.mapOptional("permissions", keys->_permissions,
DefinedAtom::permissions(
keys->_contentType));
io.mapOptional("references", keys->_references);
}
};
template <> struct MappingTraits<lld::DefinedAtom *> {
static void mapping(IO &io, lld::DefinedAtom *&atom) {
const lld::DefinedAtom *atomPtr = atom;
MappingTraits<const lld::DefinedAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::DefinedAtom *>(atomPtr);
}
};
// YAML conversion for const lld::UndefinedAtom*
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<const lld::UndefinedAtom *> {
class NormalizedAtom : public lld::UndefinedAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _canBeNull(canBeNullNever) {}
NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
2013-09-12 06:21:42 +08:00
: _file(fileFromContext(io)), _name(atom->name()),
_canBeNull(atom->canBeNull()) {}
~NormalizedAtom() override = default;
const lld::UndefinedAtom *denormalize(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
2013-09-12 06:21:42 +08:00
if (!_name.empty())
_name = f->copyString(_name);
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created UndefinedAtom named: '" << _name
<< "' (" << (const void *)_name.data() << ", "
<< _name.size() << ")\n");
return this;
}
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
[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->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
CanBeNull canBeNull() const override { return _canBeNull; }
const lld::File &_file;
StringRef _name;
CanBeNull _canBeNull;
};
2013-09-12 06:21:42 +08:00
static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
2013-09-12 06:21:42 +08:00
MappingNormalizationHeap<NormalizedAtom, const lld::UndefinedAtom *> keys(
io, atom, &info->_file->allocator());
io.mapRequired("name", keys->_name);
2013-09-12 06:21:42 +08:00
io.mapOptional("can-be-null", keys->_canBeNull,
lld::UndefinedAtom::canBeNullNever);
}
};
template <> struct MappingTraits<lld::UndefinedAtom *> {
static void mapping(IO &io, lld::UndefinedAtom *&atom) {
const lld::UndefinedAtom *atomPtr = atom;
MappingTraits<const lld::UndefinedAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::UndefinedAtom *>(atomPtr);
}
};
// YAML conversion for const lld::SharedLibraryAtom*
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<const lld::SharedLibraryAtom *> {
class NormalizedAtom : public lld::SharedLibraryAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _canBeNull(false),
_type(Type::Unknown), _size(0) {}
NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
2013-09-12 06:21:42 +08:00
: _file(fileFromContext(io)), _name(atom->name()),
_loadName(atom->loadName()), _canBeNull(atom->canBeNullAtRuntime()),
_type(atom->type()), _size(atom->size()) {}
~NormalizedAtom() override = default;
const lld::SharedLibraryAtom *denormalize(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
2013-09-12 06:21:42 +08:00
if (!_name.empty())
_name = f->copyString(_name);
2013-09-12 06:21:42 +08:00
if (!_loadName.empty())
_loadName = f->copyString(_loadName);
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created SharedLibraryAtom named: '"
<< _name << "' ("
<< (const void *)_name.data()
2013-09-12 06:21:42 +08:00
<< ", " << _name.size() << ")\n");
return this;
}
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
[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->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
StringRef loadName() const override { return _loadName; }
bool canBeNullAtRuntime() const override { return _canBeNull; }
Type type() const override { return _type; }
uint64_t size() const override { return _size; }
2013-09-12 06:21:42 +08:00
const lld::File &_file;
StringRef _name;
StringRef _loadName;
ShlibCanBeNull _canBeNull;
Type _type;
uint64_t _size;
};
static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
2013-09-12 06:21:42 +08:00
MappingNormalizationHeap<NormalizedAtom, const lld::SharedLibraryAtom *>
keys(io, atom, &info->_file->allocator());
io.mapRequired("name", keys->_name);
io.mapOptional("load-name", keys->_loadName);
2013-09-12 06:21:42 +08:00
io.mapOptional("can-be-null", keys->_canBeNull, (ShlibCanBeNull) false);
io.mapOptional("type", keys->_type, SharedLibraryAtom::Type::Code);
io.mapOptional("size", keys->_size, uint64_t(0));
}
};
template <> struct MappingTraits<lld::SharedLibraryAtom *> {
static void mapping(IO &io, lld::SharedLibraryAtom *&atom) {
const lld::SharedLibraryAtom *atomPtr = atom;
MappingTraits<const lld::SharedLibraryAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::SharedLibraryAtom *>(atomPtr);
}
};
// YAML conversion for const lld::AbsoluteAtom*
2013-09-12 06:21:42 +08:00
template <> struct MappingTraits<const lld::AbsoluteAtom *> {
class NormalizedAtom : public lld::AbsoluteAtom {
public:
NormalizedAtom(IO &io)
: _file(fileFromContext(io)), _scope(), _value(0) {}
NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
2013-09-12 06:21:42 +08:00
: _file(fileFromContext(io)), _name(atom->name()),
_scope(atom->scope()), _value(atom->value()) {}
~NormalizedAtom() override = default;
const lld::AbsoluteAtom *denormalize(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
2013-09-12 06:21:42 +08:00
if (!_name.empty())
_name = f->copyString(_name);
2013-09-12 06:21:42 +08:00
DEBUG_WITH_TYPE("WriterYAML",
llvm::dbgs() << "created AbsoluteAtom named: '" << _name
<< "' (" << (const void *)_name.data()
<< ", " << _name.size() << ")\n");
return this;
}
// Extract current File object from YAML I/O parsing context
const lld::File &fileFromContext(IO &io) {
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
[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->_file != nullptr);
return *info->_file;
}
const lld::File &file() const override { return _file; }
StringRef name() const override { return _name; }
uint64_t value() const override { return _value; }
Scope scope() const override { return _scope; }
2013-09-12 06:21:42 +08:00
const lld::File &_file;
StringRef _name;
StringRef _refName;
Scope _scope;
Hex64 _value;
};
static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
2013-09-12 06:21:42 +08:00
MappingNormalizationHeap<NormalizedAtom, const lld::AbsoluteAtom *> keys(
io, atom, &info->_file->allocator());
2013-09-12 06:21:42 +08:00
if (io.outputting()) {
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
assert(f);
assert(f->_rnb);
2013-09-12 06:21:42 +08:00
if (f->_rnb->hasRefName(atom)) {
keys->_refName = f->_rnb->refName(atom);
}
}
io.mapRequired("name", keys->_name);
2013-09-12 06:21:42 +08:00
io.mapOptional("ref-name", keys->_refName, StringRef());
io.mapOptional("scope", keys->_scope);
io.mapRequired("value", keys->_value);
}
};
template <> struct MappingTraits<lld::AbsoluteAtom *> {
static void mapping(IO &io, lld::AbsoluteAtom *&atom) {
const lld::AbsoluteAtom *atomPtr = atom;
MappingTraits<const lld::AbsoluteAtom *>::mapping(io, atomPtr);
atom = const_cast<lld::AbsoluteAtom *>(atomPtr);
}
};
} // end namespace llvm
} // end namespace yaml
RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
NormalizedAtom;
for (const lld::DefinedAtom *a : file->defined()) {
const auto *na = (const NormalizedAtom *)a;
if (!na->_refName.empty())
add(na->_refName, a);
else if (!na->_name.empty())
add(na->_name, a);
}
2013-09-12 06:21:42 +08:00
for (const lld::UndefinedAtom *a : file->undefined())
add(a->name(), a);
2013-09-12 06:21:42 +08:00
for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
add(a->name(), a);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::AbsoluteAtom *>::NormalizedAtom NormAbsAtom;
for (const lld::AbsoluteAtom *a : file->absolute()) {
const auto *na = (const NormAbsAtom *)a;
2013-09-12 06:21:42 +08:00
if (na->_refName.empty())
add(na->_name, a);
else
add(na->_refName, a);
2013-09-12 06:21:42 +08:00
}
}
2013-09-12 06:21:42 +08:00
inline const lld::File *
MappingTraits<const lld::File *>::NormalizedFile::denormalize(IO &io) {
typedef MappingTraits<const lld::DefinedAtom *>::NormalizedAtom
NormalizedAtom;
RefNameResolver nameResolver(this, io);
// Now that all atoms are parsed, references can be bound.
2013-09-12 06:21:42 +08:00
for (const lld::DefinedAtom *a : this->defined()) {
auto *normAtom = (NormalizedAtom *)const_cast<DefinedAtom *>(a);
normAtom->bind(nameResolver);
}
return this;
}
2013-09-12 06:21:42 +08:00
inline void MappingTraits<const lld::DefinedAtom *>::NormalizedAtom::bind(
const RefNameResolver &resolver) {
typedef MappingTraits<const lld::Reference *>::NormalizedReference
NormalizedReference;
for (const lld::Reference *ref : _references) {
auto *normRef = (NormalizedReference *)const_cast<Reference *>(ref);
normRef->bind(resolver);
}
}
2013-09-12 06:21:42 +08:00
inline void MappingTraits<const lld::Reference *>::NormalizedReference::bind(
const RefNameResolver &resolver) {
_target = resolver.lookup(_targetName);
}
inline StringRef
2013-09-12 06:21:42 +08:00
MappingTraits<const lld::Reference *>::NormalizedReference::targetName(
IO &io, const lld::Reference *ref) {
if (ref->target() == nullptr)
return StringRef();
[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 *info = reinterpret_cast<YamlContext *>(io.getContext());
assert(info != nullptr);
2013-09-12 06:21:42 +08:00
typedef MappingTraits<const lld::File *>::NormalizedFile NormalizedFile;
[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
NormalizedFile *f = reinterpret_cast<NormalizedFile *>(info->_file);
RefNameBuilder &rnb = *f->_rnb;
if (rnb.hasRefName(ref->target()))
return rnb.refName(ref->target());
return ref->target()->name();
}
namespace lld {
namespace yaml {
class Writer : public lld::Writer {
public:
Writer(const LinkingContext &context) : _ctx(context) {}
llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
// Create stream to path.
std::error_code ec;
llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
if (ec)
return llvm::errorCodeToError(ec);
// 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._ctx = &_ctx;
yamlContext._registry = &_ctx.registry();
[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
llvm::yaml::Output yout(out, &yamlContext);
// Write yaml output.
const lld::File *fileRef = &file;
yout << fileRef;
return llvm::Error::success();
}
private:
const LinkingContext &_ctx;
};
[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
} // end namespace yaml
namespace {
/// Handles !native tagged yaml documents.
class NativeYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
if (io.mapTag("!native")) {
MappingTraits<const lld::File *>::mappingAtoms(io, file);
return true;
}
return false;
}
};
/// Handles !archive tagged yaml documents.
class ArchiveYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override {
if (io.mapTag("!archive")) {
MappingTraits<const lld::File *>::mappingArchive(io, file);
return true;
}
return false;
}
};
[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
class YAMLReader : public Reader {
public:
YAMLReader(const Registry &registry) : _registry(registry) {}
bool canParse(file_magic magic, MemoryBufferRef mb) const override {
2015-10-02 21:23:29 +08:00
StringRef name = mb.getBufferIdentifier();
return name.endswith(".objtxt") || name.endswith(".yaml");
[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
}
ErrorOr<std::unique_ptr<File>>
loadFile(std::unique_ptr<MemoryBuffer> mb,
const class Registry &) const override {
[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
// Create YAML Input Reader.
YamlContext yamlContext;
yamlContext._registry = &_registry;
yamlContext._path = mb->getBufferIdentifier();
[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
llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
// Fill vector with File objects created by parsing yaml.
2013-09-12 06:21:42 +08:00
std::vector<const lld::File *> createdFiles;
yin >> createdFiles;
assert(createdFiles.size() == 1);
[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
// Error out now if there were parsing errors.
2013-09-12 06:21:42 +08:00
if (yin.error())
return make_error_code(lld::YamlReaderError::illegal_value);
std::shared_ptr<MemoryBuffer> smb(mb.release());
const File *file = createdFiles[0];
// Note: loadFile() should return vector of *const* File
File *f = const_cast<File *>(file);
f->setLastError(std::error_code());
f->setSharedMemoryBuffer(smb);
return std::unique_ptr<File>(f);
}
[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
private:
const Registry &_registry;
};
[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
} // end anonymous namespace
[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
void Registry::addSupportYamlFiles() {
add(std::unique_ptr<Reader>(new YAMLReader(*this)));
add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
new NativeYamlIOTaggedDocumentHandler()));
add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
new ArchiveYamlIOTaggedDocumentHandler()));
[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
}
std::unique_ptr<Writer> createWriterYAML(const LinkingContext &context) {
return std::unique_ptr<Writer>(new lld::yaml::Writer(context));
}
} // end namespace lld