| //===- 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" |
| #include <atomic> |
| |
| namespace lld { |
| |
| class SimpleFile : public File { |
| public: |
| SimpleFile(StringRef path) : File(path, kindObject) {} |
| |
| void addAtom(const DefinedAtom &a) { _defined.push_back(&a); } |
| void addAtom(const UndefinedAtom &a) { _undefined.push_back(&a); } |
| void addAtom(const SharedLibraryAtom &a) { _shared.push_back(&a); } |
| void addAtom(const AbsoluteAtom &a) { _absolute.push_back(&a); } |
| |
| void addAtom(const Atom &atom) { |
| if (auto *p = dyn_cast<DefinedAtom>(&atom)) { |
| _defined.push_back(p); |
| } else if (auto *p = dyn_cast<UndefinedAtom>(&atom)) { |
| _undefined.push_back(p); |
| } else if (auto *p = dyn_cast<SharedLibraryAtom>(&atom)) { |
| _shared.push_back(p); |
| } else if (auto *p = dyn_cast<AbsoluteAtom>(&atom)) { |
| _absolute.push_back(p); |
| } else { |
| llvm_unreachable("atom has unknown definition kind"); |
| } |
| } |
| |
| void removeDefinedAtomsIf(std::function<bool(const DefinedAtom *)> pred) { |
| auto &atoms = _defined; |
| auto newEnd = std::remove_if(atoms.begin(), atoms.end(), pred); |
| atoms.erase(newEnd, atoms.end()); |
| } |
| |
| const AtomVector<DefinedAtom> &defined() const override { return _defined; } |
| |
| const AtomVector<UndefinedAtom> &undefined() const override { |
| return _undefined; |
| } |
| |
| const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { |
| return _shared; |
| } |
| |
| const AtomVector<AbsoluteAtom> &absolute() const override { |
| return _absolute; |
| } |
| |
| typedef range<std::vector<const DefinedAtom *>::iterator> DefinedAtomRange; |
| DefinedAtomRange definedAtoms() { return make_range(_defined); } |
| |
| private: |
| AtomVector<DefinedAtom> _defined; |
| AtomVector<UndefinedAtom> _undefined; |
| AtomVector<SharedLibraryAtom> _shared; |
| AtomVector<AbsoluteAtom> _absolute; |
| }; |
| |
| /// \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 AtomVector<DefinedAtom> &defined() const override { |
| return _definedAtoms; |
| } |
| |
| const AtomVector<UndefinedAtom> &undefined() const override { |
| return _undefinedAtoms; |
| } |
| |
| const AtomVector<SharedLibraryAtom> &sharedLibrary() const override { |
| return _sharedLibraryAtoms; |
| } |
| |
| const AtomVector<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: |
| AtomVector<DefinedAtom> _definedAtoms; |
| AtomVector<UndefinedAtom> _undefinedAtoms; |
| AtomVector<SharedLibraryAtom> _sharedLibraryAtoms; |
| AtomVector<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), _ordinal(f.getNextAtomOrdinalAndIncrement()) { |
| _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 1; } |
| |
| 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 |