summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/TargetLayout.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/TargetLayout.h')
-rw-r--r--lib/ReaderWriter/ELF/TargetLayout.h317
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