diff options
Diffstat (limited to 'lib/ReaderWriter/ELF/TargetLayout.h')
| -rw-r--r-- | lib/ReaderWriter/ELF/TargetLayout.h | 317 |
1 files changed, 308 insertions, 9 deletions
diff --git a/lib/ReaderWriter/ELF/TargetLayout.h b/lib/ReaderWriter/ELF/TargetLayout.h index ab7a7890a2747..52512f8e279e2 100644 --- a/lib/ReaderWriter/ELF/TargetLayout.h +++ b/lib/ReaderWriter/ELF/TargetLayout.h @@ -7,21 +7,320 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_READER_WRITER_ELF_TARGET_LAYOUT_H -#define LLD_READER_WRITER_ELF_TARGET_LAYOUT_H +#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H +#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H -#include "DefaultLayout.h" -#include "lld/Core/LLVM.h" +#include "Atoms.h" +#include "HeaderChunks.h" +#include "SectionChunks.h" +#include "SegmentChunks.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <unordered_map> namespace lld { namespace elf { -/// \brief The target can override certain functions in the DefaultLayout -/// class so that the order, the name of the section and the segment type could -/// be changed in the final layout -template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> { + +/// \brief The TargetLayout class is used by the Writer to arrange +/// sections and segments in the order determined by the target ELF +/// format. The writer creates a single instance of the TargetLayout +/// class +template <class ELFT> class TargetLayout { +public: + typedef uint32_t SectionOrder; + typedef uint32_t SegmentType; + + // The order in which the sections appear in the output file + // If its determined, that the layout needs to change + // just changing the order of enumerations would essentially + // change the layout in the output file + // Change the enumerations so that Target can override and stick + // a section anywhere it wants to + enum DefaultSectionOrder { + ORDER_NOT_DEFINED = 0, + ORDER_INTERP = 10, + ORDER_RO_NOTE = 15, + ORDER_HASH = 30, + ORDER_DYNAMIC_SYMBOLS = 40, + ORDER_DYNAMIC_STRINGS = 50, + ORDER_DYNAMIC_RELOCS = 52, + ORDER_DYNAMIC_PLT_RELOCS = 54, + ORDER_INIT = 60, + ORDER_PLT = 70, + ORDER_TEXT = 80, + ORDER_FINI = 90, + ORDER_REL = 95, + ORDER_RODATA = 100, + ORDER_EH_FRAME = 110, + ORDER_EH_FRAMEHDR = 120, + ORDER_TDATA = 124, + ORDER_TBSS = 128, + ORDER_CTORS = 130, + ORDER_DTORS = 140, + ORDER_INIT_ARRAY = 150, + ORDER_FINI_ARRAY = 160, + ORDER_DYNAMIC = 170, + ORDER_GOT = 180, + ORDER_GOT_PLT = 190, + ORDER_DATA = 200, + ORDER_RW_NOTE = 205, + ORDER_BSS = 210, + ORDER_NOALLOC = 215, + ORDER_OTHER = 220, + ORDER_SECTION_STRINGS = 230, + ORDER_SYMBOL_TABLE = 240, + ORDER_STRING_TABLE = 250, + ORDER_SECTION_HEADERS = 260 + }; + public: - TargetLayout(ELFLinkingContext &context) : DefaultLayout<ELFT>(context) {} + + // The Key used for creating Sections + // The sections are created using + // SectionName, contentPermissions + struct SectionKey { + SectionKey(StringRef name, DefinedAtom::ContentPermissions perm, + StringRef path) + : _name(name), _perm(perm), _path(path) {} + + // Data members + StringRef _name; + DefinedAtom::ContentPermissions _perm; + StringRef _path; + }; + + struct SectionKeyHash { + int64_t operator()(const SectionKey &k) const { + return llvm::hash_combine(k._name, k._perm, k._path); + } + }; + + struct SectionKeyEq { + bool operator()(const SectionKey &lhs, const SectionKey &rhs) const { + return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm) && + (lhs._path == rhs._path)); + } + }; + + typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter; + typedef typename std::vector<Segment<ELFT> *>::iterator SegmentIter; + + // Properties used during segment creation + struct SegmentKey { + SegmentKey(StringRef name, int64_t type, uint64_t flags, bool segFlags) + : _name(name), _type(type), _flags(flags), + _segmentFlags(segFlags && flags != 0) {} + StringRef _name = ""; + int64_t _type = 0; + uint64_t _flags = 0; + bool _segmentFlags = false; + }; + + struct SegmentKeyHash { + int64_t operator()(const SegmentKey &k) const { + return llvm::hash_combine(k._name, k._type, k._flags); + } + }; + + struct SegmentKeyEq { + bool operator()(const SegmentKey &lhs, const SegmentKey &rhs) const { + return ((lhs._name == rhs._name) && (lhs._type == rhs._type) && + (lhs._flags == rhs._flags)); + } + }; + + // Output Sections contain the map of Section names to a vector of sections, + // that have been merged to form a single section + typedef llvm::StringMap<OutputSection<ELFT> *> OutputSectionMapT; + typedef + typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter; + + typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash, + SectionKeyEq> SectionMapT; + typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentKeyHash, + SegmentKeyEq> SegmentMapT; + + typedef typename std::vector<AtomLayout *>::iterator AbsoluteAtomIterT; + + typedef llvm::DenseSet<const Atom *> AtomSetT; + + TargetLayout(ELFLinkingContext &ctx) + : _ctx(ctx), _linkerScriptSema(ctx.linkerScriptSema()) {} + + virtual ~TargetLayout() = default; + + /// \brief Return the section order for a input section + virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType, + int32_t contentPermissions); + + /// \brief Return the name of the input section by decoding the input + /// sectionChoice. + virtual StringRef getInputSectionName(const DefinedAtom *da) const; + + /// \brief Return the name of the output section from the input section. + virtual StringRef getOutputSectionName(StringRef archivePath, + StringRef memberPath, + StringRef inputSectionName) const; + + /// \brief Gets or creates a section. + AtomSection<ELFT> * + getSection(StringRef name, int32_t contentType, + DefinedAtom::ContentPermissions contentPermissions, + const DefinedAtom *da); + + /// \brief Gets the segment for a output section + virtual SegmentType getSegmentType(const Section<ELFT> *section) const; + + /// \brief Returns true/false depending on whether the section has a Output + // segment or not + static bool hasOutputSegment(Section<ELFT> *section); + + /// \brief Append the Atom to the layout and create appropriate sections. + /// \returns A reference to the atom layout or an error. The atom layout will + /// be updated as linking progresses. + virtual ErrorOr<const AtomLayout *> addAtom(const Atom *atom); + + /// \brief Find an output Section given a section name. + OutputSection<ELFT> *findOutputSection(StringRef name) { + auto iter = _outputSectionMap.find(name); + if (iter == _outputSectionMap.end()) + return nullptr; + return iter->second; + } + + /// \brief find a absolute atom given a name + AtomLayout *findAbsoluteAtom(StringRef name) { + auto iter = std::find_if( + _absoluteAtoms.begin(), _absoluteAtoms.end(), + [=](const AtomLayout *a) { return a->_atom->name() == name; }); + if (iter == _absoluteAtoms.end()) + return nullptr; + return *iter; + } + + // Output sections with the same name into a OutputSection + void createOutputSections(); + + // Query for segments based on output and input sections + std::vector<SegmentKey> getSegmentsForSection(const OutputSection<ELFT> *os, + const Section<ELFT> *sec) const; + + /// \brief Sort the sections by their order as defined by the layout, + /// preparing all sections to be assigned to a segment. + virtual void sortInputSections(); + + /// \brief Add extra chunks to a segment just before including the input + /// section given by <archivePath, memberPath, sectionName>. This + /// is used to add linker script expressions before each section. + virtual void addExtraChunksToSegment(Segment<ELFT> *segment, + StringRef archivePath, + StringRef memberPath, + StringRef sectionName); + + /// \brief associates a section to a segment + virtual void assignSectionsToSegments(); + + /// \brief associates a virtual address to the segment, section, and the atom + virtual void assignVirtualAddress(); + + void assignFileOffsetsForMiscSections(); + + range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; } + + void addSection(Chunk<ELFT> *c) { _sections.push_back(c); } + + void finalize() { + ScopedTask task(getDefaultDomain(), "Finalize layout"); + for (auto &si : _sections) + si->finalize(); + } + + void doPreFlight() { + for (auto &si : _sections) + si->doPreFlight(); + } + + /// \brief find the Atom in the current layout + virtual const AtomLayout *findAtomLayoutByName(StringRef name) const; + + void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; } + + void setProgramHeader(ProgramHeader<ELFT> *p) { + _programHeader = p; + } + + range<OutputSectionIter> outputSections() { return _outputSections; } + + range<ChunkIter> sections() { return _sections; } + + range<SegmentIter> segments() { return _segments; } + + ELFHeader<ELFT> *getHeader() { return _elfHeader; } + + bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; } + + bool hasPLTRelocationTable() const { return !!_pltRelocationTable; } + + /// \brief Get or create the dynamic relocation table. All relocations in this + /// table are processed at startup. + RelocationTable<ELFT> *getDynamicRelocationTable(); + + /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL. + RelocationTable<ELFT> *getPLTRelocationTable(); + + uint64_t getTLSSize() const; + + bool isReferencedByDefinedAtom(const Atom *a) const { + return _referencedDynAtoms.count(a); + } + + bool isCopied(const SharedLibraryAtom *sla) const { + return _copiedDynSymNames.count(sla->name()); + } + +protected: + /// \brief TargetLayouts may use these functions to reorder the input sections + /// in a order defined by their ABI. + virtual void finalizeOutputSectionLayout() {} + + /// \brief Allocate a new section. + virtual AtomSection<ELFT> *createSection( + StringRef name, int32_t contentType, + DefinedAtom::ContentPermissions contentPermissions, + SectionOrder sectionOrder); + + /// \brief Create a new relocation table. + virtual unique_bump_ptr<RelocationTable<ELFT>> + createRelocationTable(StringRef name, int32_t order) { + return unique_bump_ptr<RelocationTable<ELFT>>( + new (_allocator) RelocationTable<ELFT>(_ctx, name, order)); + } + + virtual uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const; + + /// \brief Sort segements stored in the _segments + virtual void sortSegments(); + +protected: + llvm::BumpPtrAllocator _allocator; + SectionMapT _sectionMap; + OutputSectionMapT _outputSectionMap; + SegmentMapT _segmentMap; + std::vector<Chunk<ELFT> *> _sections; + std::vector<Segment<ELFT> *> _segments; + std::vector<OutputSection<ELFT> *> _outputSections; + ELFHeader<ELFT> *_elfHeader; + ProgramHeader<ELFT> *_programHeader; + unique_bump_ptr<RelocationTable<ELFT>> _dynamicRelocationTable; + unique_bump_ptr<RelocationTable<ELFT>> _pltRelocationTable; + std::vector<AtomLayout *> _absoluteAtoms; + AtomSetT _referencedDynAtoms; + llvm::StringSet<> _copiedDynSymNames; + ELFLinkingContext &_ctx; + script::Sema &_linkerScriptSema; }; + } // end namespace elf } // end namespace lld |
