summaryrefslogtreecommitdiff
path: root/include/lld/Core/Simple.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/lld/Core/Simple.h')
-rw-r--r--include/lld/Core/Simple.h341
1 files changed, 341 insertions, 0 deletions
diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h
new file mode 100644
index 000000000000..71d0c0702301
--- /dev/null
+++ b/include/lld/Core/Simple.h
@@ -0,0 +1,341 @@
+//===- lld/Core/Simple.h - Simple implementations of Atom and File --------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Provide simple implementations for Atoms and File.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_SIMPLE_H
+#define LLD_CORE_SIMPLE_H
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/ArchiveLibraryFile.h"
+#include "lld/Core/LinkingContext.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/UndefinedAtom.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
+
+namespace lld {
+
+class SimpleFile : public MutableFile {
+public:
+ SimpleFile(StringRef path) : MutableFile(path) {}
+
+ void addAtom(const Atom &atom) override {
+ if (auto *defAtom = dyn_cast<DefinedAtom>(&atom)) {
+ _definedAtoms._atoms.push_back(defAtom);
+ } else if (auto *undefAtom = dyn_cast<UndefinedAtom>(&atom)) {
+ _undefinedAtoms._atoms.push_back(undefAtom);
+ } else if (auto *shlibAtom = dyn_cast<SharedLibraryAtom>(&atom)) {
+ _sharedLibraryAtoms._atoms.push_back(shlibAtom);
+ } else if (auto *absAtom = dyn_cast<AbsoluteAtom>(&atom)) {
+ _absoluteAtoms._atoms.push_back(absAtom);
+ } else {
+ llvm_unreachable("atom has unknown definition kind");
+ }
+ }
+
+ void
+ removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) override {
+ auto &atoms = _definedAtoms._atoms;
+ auto newEnd = std::remove_if(atoms.begin(), atoms.end(), pred);
+ atoms.erase(newEnd, atoms.end());
+ }
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ DefinedAtomRange definedAtoms() override {
+ return make_range(_definedAtoms._atoms);
+ }
+
+private:
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+/// \brief Archive library file that may be used as a virtual container
+/// for symbols that should be added dynamically in response to
+/// call to find() method.
+class SimpleArchiveLibraryFile : public ArchiveLibraryFile {
+public:
+ SimpleArchiveLibraryFile(StringRef filename)
+ : ArchiveLibraryFile(filename) {}
+
+ const atom_collection<DefinedAtom> &defined() const override {
+ return _definedAtoms;
+ }
+
+ const atom_collection<UndefinedAtom> &undefined() const override {
+ return _undefinedAtoms;
+ }
+
+ const atom_collection<SharedLibraryAtom> &sharedLibrary() const override {
+ return _sharedLibraryAtoms;
+ }
+
+ const atom_collection<AbsoluteAtom> &absolute() const override {
+ return _absoluteAtoms;
+ }
+
+ File *find(StringRef sym, bool dataSymbolOnly) override {
+ // For descendants:
+ // do some checks here and return dynamically generated files with atoms.
+ return nullptr;
+ }
+
+ std::error_code
+ parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
+ return std::error_code();
+ }
+
+private:
+ atom_collection_vector<DefinedAtom> _definedAtoms;
+ atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+ atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+ atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+};
+
+class SimpleReference : public Reference {
+public:
+ SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue value, uint64_t off, const Atom *t,
+ Reference::Addend a)
+ : Reference(ns, arch, value), _target(t), _offsetInAtom(off), _addend(a),
+ _next(nullptr), _prev(nullptr) {
+ }
+ SimpleReference()
+ : Reference(Reference::KindNamespace::all, Reference::KindArch::all, 0),
+ _target(nullptr), _offsetInAtom(0), _addend(0), _next(nullptr),
+ _prev(nullptr) {
+ }
+
+ uint64_t offsetInAtom() const override { return _offsetInAtom; }
+
+ const Atom *target() const override {
+ assert(_target);
+ return _target;
+ }
+
+ Addend addend() const override { return _addend; }
+ void setAddend(Addend a) override { _addend = a; }
+ void setTarget(const Atom *newAtom) override { _target = newAtom; }
+ SimpleReference *getNext() const { return _next; }
+ SimpleReference *getPrev() const { return _prev; }
+ void setNext(SimpleReference *n) { _next = n; }
+ void setPrev(SimpleReference *p) { _prev = p; }
+
+private:
+ const Atom *_target;
+ uint64_t _offsetInAtom;
+ Addend _addend;
+ SimpleReference *_next;
+ SimpleReference *_prev;
+};
+
+}
+
+// ilist will lazily create a sentinal (so end() can return a node past the
+// end of the list). We need this trait so that the sentinal is allocated
+// via the BumpPtrAllocator.
+namespace llvm {
+template<>
+struct ilist_sentinel_traits<lld::SimpleReference> {
+
+ ilist_sentinel_traits() : _allocator(nullptr) { }
+
+ void setAllocator(llvm::BumpPtrAllocator *alloc) {
+ _allocator = alloc;
+ }
+
+ lld::SimpleReference *createSentinel() const {
+ return new (*_allocator) lld::SimpleReference();
+ }
+
+ static void destroySentinel(lld::SimpleReference*) {}
+
+ static lld::SimpleReference *provideInitialHead() { return nullptr; }
+
+ lld::SimpleReference *ensureHead(lld::SimpleReference *&head) const {
+ if (!head) {
+ head = createSentinel();
+ noteHead(head, head);
+ ilist_traits<lld::SimpleReference>::setNext(head, nullptr);
+ return head;
+ }
+ return ilist_traits<lld::SimpleReference>::getPrev(head);
+ }
+
+ void noteHead(lld::SimpleReference *newHead,
+ lld::SimpleReference *sentinel) const {
+ ilist_traits<lld::SimpleReference>::setPrev(newHead, sentinel);
+ }
+
+private:
+ mutable llvm::BumpPtrAllocator *_allocator;
+};
+}
+
+namespace lld {
+
+class SimpleDefinedAtom : public DefinedAtom {
+public:
+ explicit SimpleDefinedAtom(const File &f) : _file(f) {
+ static uint32_t lastOrdinal = 0;
+ _ordinal = lastOrdinal++;
+ _references.setAllocator(&f.allocator());
+ }
+
+ const File &file() const override { return _file; }
+
+ StringRef name() const override { return StringRef(); }
+
+ uint64_t ordinal() const override { return _ordinal; }
+
+ Scope scope() const override { return DefinedAtom::scopeLinkageUnit; }
+
+ Interposable interposable() const override {
+ return DefinedAtom::interposeNo;
+ }
+
+ Merge merge() const override { return DefinedAtom::mergeNo; }
+
+ Alignment alignment() const override { return Alignment(0, 0); }
+
+ SectionChoice sectionChoice() const override {
+ return DefinedAtom::sectionBasedOnContent;
+ }
+
+ StringRef customSectionName() const override { return StringRef(); }
+ DeadStripKind deadStrip() const override {
+ return DefinedAtom::deadStripNormal;
+ }
+
+ DefinedAtom::reference_iterator begin() const override {
+ const void *it = reinterpret_cast<const void *>(&*_references.begin());
+ return reference_iterator(*this, it);
+ }
+
+ DefinedAtom::reference_iterator end() const override {
+ const void *it = reinterpret_cast<const void *>(&*_references.end());
+ return reference_iterator(*this, it);
+ }
+
+ const Reference *derefIterator(const void *it) const override {
+ return reinterpret_cast<const Reference*>(it);
+ }
+
+ void incrementIterator(const void *&it) const override {
+ const SimpleReference* node = reinterpret_cast<const SimpleReference*>(it);
+ const SimpleReference* next = node->getNext();
+ it = reinterpret_cast<const void*>(next);
+ }
+
+ void addReference(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t off,
+ const Atom *target, Reference::Addend a) {
+ assert(target && "trying to create reference to nothing");
+ auto node = new (_file.allocator())
+ SimpleReference(ns, arch, kindValue, off, target, a);
+ _references.push_back(node);
+ }
+
+ /// Sort references in a canonical order (by offset, then by kind).
+ void sortReferences() const {
+ // Cannot sort a linked list, so move elements into a temporary vector,
+ // sort the vector, then reconstruct the list.
+ llvm::SmallVector<SimpleReference *, 16> elements;
+ for (SimpleReference &node : _references) {
+ elements.push_back(&node);
+ }
+ std::sort(elements.begin(), elements.end(),
+ [] (const SimpleReference *lhs, const SimpleReference *rhs) -> bool {
+ uint64_t lhsOffset = lhs->offsetInAtom();
+ uint64_t rhsOffset = rhs->offsetInAtom();
+ if (rhsOffset != lhsOffset)
+ return (lhsOffset < rhsOffset);
+ if (rhs->kindNamespace() != lhs->kindNamespace())
+ return (lhs->kindNamespace() < rhs->kindNamespace());
+ if (rhs->kindArch() != lhs->kindArch())
+ return (lhs->kindArch() < rhs->kindArch());
+ return (lhs->kindValue() < rhs->kindValue());
+ });
+ _references.clearAndLeakNodesUnsafely();
+ for (SimpleReference *node : elements) {
+ _references.push_back(node);
+ }
+ }
+ void setOrdinal(uint64_t ord) { _ordinal = ord; }
+
+private:
+ typedef llvm::ilist<SimpleReference> RefList;
+
+ const File &_file;
+ uint64_t _ordinal;
+ mutable RefList _references;
+};
+
+class SimpleUndefinedAtom : public UndefinedAtom {
+public:
+ SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) {
+ assert(!name.empty() && "UndefinedAtoms must have a name");
+ }
+
+ /// file - returns the File that produced/owns this Atom
+ const File &file() const override { return _file; }
+
+ /// name - The name of the atom. For a function atom, it is the (mangled)
+ /// name of the function.
+ StringRef name() const override { return _name; }
+
+ CanBeNull canBeNull() const override { return UndefinedAtom::canBeNullNever; }
+
+private:
+ const File &_file;
+ StringRef _name;
+};
+
+class SimpleAbsoluteAtom : public AbsoluteAtom {
+public:
+ SimpleAbsoluteAtom(const File &f, StringRef name, Scope s, uint64_t value)
+ : _file(f), _name(name), _scope(s), _value(value) {}
+
+ const 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; }
+
+private:
+ const File &_file;
+ StringRef _name;
+ Scope _scope;
+ uint64_t _value;
+};
+
+} // end namespace lld
+
+#endif