//===- lib/ReaderWriter/ELF/SegmentChunks.h -------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H #define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H #include "Chunk.h" #include "SectionChunks.h" #include "Writer.h" #include "lld/Core/range.h" #include "lld/Core/Writer.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" #include namespace lld { namespace elf { template class TargetLayout; /// \brief A segment can be divided into segment slices /// depending on how the segments can be split template class SegmentSlice { public: typedef typename std::vector *>::iterator SectionIter; /// Set the start of the slice. void setStart(int32_t s) { _startSection = s; } // Set the segment slice start and end iterators. This is used to walk through // the sections that are part of the Segment slice void setSections(range sections) { _sections = sections; } // Return the fileOffset of the slice uint64_t fileOffset() const { return _offset; } void setFileOffset(uint64_t offset) { _offset = offset; } // Return the size of the slice uint64_t fileSize() const { return _fsize; } void setFileSize(uint64_t filesz) { _fsize = filesz; } // Return the start of the slice int32_t startSection() const { return _startSection; } // Return the start address of the slice uint64_t virtualAddr() const { return _addr; } // Return the memory size of the slice uint64_t memSize() const { return _memSize; } // Return the alignment of the slice uint64_t alignment() const { return _alignment; } void setMemSize(uint64_t memsz) { _memSize = memsz; } void setVirtualAddr(uint64_t addr) { _addr = addr; } void setAlign(uint64_t align) { _alignment = align; } static bool compare_slices(SegmentSlice *a, SegmentSlice *b); range sections() { return _sections; } private: range _sections; int32_t _startSection; uint64_t _addr; uint64_t _offset; uint64_t _alignment; uint64_t _fsize; uint64_t _memSize; }; /// \brief A segment contains a set of sections, that have similar properties // the sections are already separated based on different flags and properties // the segment is just a way to concatenate sections to segments template class Segment : public Chunk { public: typedef typename std::vector *>::iterator SliceIter; typedef typename std::vector *>::iterator SectionIter; Segment(const ELFLinkingContext &ctx, StringRef name, const typename TargetLayout::SegmentType type); /// \brief the Order of segments that appear in the output file enum SegmentOrder { permUnknown, permRWX, permRX, permR, permRWL, permRW, permNonAccess }; /// append a section to a segment virtual void append(Chunk *chunk); /// Sort segments depending on the property /// If we have a Program Header segment, it should appear first /// If we have a INTERP segment, that should appear after the Program Header /// All Loadable segments appear next in this order /// All Read Write Execute segments follow /// All Read Execute segments appear next /// All Read only segments appear first /// All Write execute segments follow static bool compareSegments(Segment *sega, Segment *segb); /// \brief Start assigning file offset to the segment chunks The fileoffset /// needs to be page at the start of the segment and in addition the /// fileoffset needs to be aligned to the max section alignment within the /// segment. This is required so that the ELF property p_poffset % p_align = /// p_vaddr mod p_align holds true. /// The algorithm starts off by assigning the startOffset thats passed in as /// parameter to the first section in the segment, if the difference between /// the newly computed offset is greater than a page, then we create a segment /// slice, as it would be a waste of virtual memory just to be filled with /// zeroes void assignFileOffsets(uint64_t startOffset); /// \brief Assign virtual addresses to the slices void assignVirtualAddress(uint64_t addr); // Write the Segment void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) override; int64_t flags() const; // Set segment flags directly. void setSegmentFlags(uint64_t flags); /// Prepend a generic chunk to the segment. void prepend(Chunk *c) { _sections.insert(_sections.begin(), c); } /// Finalize the segment, before we want to write the segment header /// information void finalize() override; // For LLVM RTTI static bool classof(const Chunk *c) { return c->kind() == Chunk::Kind::ELFSegment; } // Getters int32_t sectionCount() const { return _sections.size(); } /// \brief, this function returns the type of segment (PT_*) typename TargetLayout::SegmentType segmentType() const { return _segmentType; } /// \brief return the segment type depending on the content, /// If the content corresponds to Code, this will return Segment::Code /// If the content corresponds to Data, this will return Segment::Data /// If the content corresponds to TLS, this will return Segment::TLS int getContentType() const override; int pageSize() const { return this->_ctx.getPageSize(); } int rawflags() const { return _atomflags; } int64_t atomflags() const; int64_t numSlices() const { return _segmentSlices.size(); } range slices() { return _segmentSlices; } Chunk *firstSection() { return _sections[0]; } private: /// \brief Check if the chunk needs to be aligned bool needAlign(Chunk *chunk) const; // Cached value of outputMagic ELFLinkingContext::OutputMagic _outputMagic; protected: /// \brief Section or some other chunk type. std::vector *> _sections; std::vector *> _segmentSlices; typename TargetLayout::SegmentType _segmentType; uint64_t _flags; int64_t _atomflags; bool _segmentFlags; llvm::BumpPtrAllocator _segmentAllocate; }; /// This chunk represents a linker script expression that needs to be calculated /// at the time the virtual addresses for the parent segment are being assigned. template class ExpressionChunk : public Chunk { public: ExpressionChunk(ELFLinkingContext &ctx, const script::SymbolAssignment *expr) : Chunk(StringRef(), Chunk::Kind::Expression, ctx), _expr(expr), _linkerScriptSema(ctx.linkerScriptSema()) { this->_alignment = 1; } static bool classof(const Chunk *c) { return c->kind() == Chunk::Kind::Expression; } int getContentType() const override { return Chunk::ContentType::Unknown; } void write(ELFWriter *, TargetLayout &, llvm::FileOutputBuffer &) override {} std::error_code evalExpr(uint64_t &curPos) { return _linkerScriptSema.evalExpr(_expr, curPos); } private: const script::SymbolAssignment *_expr; script::Sema &_linkerScriptSema; }; /// \brief A Program Header segment contains a set of chunks instead of sections /// The segment doesn't contain any slice template class ProgramHeaderSegment : public Segment { public: ProgramHeaderSegment(const ELFLinkingContext &ctx) : Segment(ctx, "PHDR", llvm::ELF::PT_PHDR) { this->_alignment = 8; this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR); } /// Finalize the segment, before we want to write the segment header /// information void finalize() override; }; } // end namespace elf } // end namespace lld #endif // LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H