//===- MCSection.h - Machine Code Sections ----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares the MCSection class. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCSECTION_H #define LLVM_MC_MCSECTION_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Compiler.h" #include #include namespace llvm { class MCAsmInfo; class MCAssembler; class MCContext; class MCExpr; class MCFragment; class MCObjectStreamer; class MCSymbol; class MCSection; class MCSubtargetInfo; class raw_ostream; class Triple; // Represents a contiguous piece of code or data within a section. Its size is // determined by MCAssembler::layout. All subclasses must have trivial // destructors. class MCFragment { friend class MCAssembler; friend class MCStreamer; friend class MCObjectStreamer; friend class MCSection; public: enum FragmentType : uint8_t { FT_Data, FT_Relaxable, FT_Align, FT_Fill, FT_LEB, FT_Nops, FT_Org, FT_Dwarf, FT_DwarfFrame, FT_SFrame, FT_BoundaryAlign, FT_SymbolId, FT_CVInlineLines, FT_CVDefRange, }; private: // The next fragment within the section. MCFragment *Next = nullptr; /// The data for the section this fragment is in. MCSection *Parent = nullptr; /// The offset of this fragment in its section. uint64_t Offset = 0; /// The layout order of this fragment. unsigned LayoutOrder = 0; FragmentType Kind; //== Used by certain fragment types for better packing. // The number of fixups for the optional variable-size tail must be small. uint8_t VarFixupSize = 0; bool LinkerRelaxable : 1; /// FT_Data, FT_Relaxable bool HasInstructions : 1; /// FT_Relaxable, x86-specific bool AllowAutoPadding : 1; // Track content and fixups for the fixed-size part as fragments are // appended to the section. The content is stored as trailing data of the // MCFragment. The content remains immutable, except when modified by // applyFixup. uint32_t FixedSize = 0; uint32_t FixupStart = 0; uint32_t FixupEnd = 0; // Track content and fixups for the optional variable-size tail part, // typically modified during relaxation. uint32_t VarContentStart = 0; uint32_t VarContentEnd = 0; uint32_t VarFixupStart = 0; protected: const MCSubtargetInfo *STI = nullptr; private: // Optional variable-size tail used by various fragment types. union Tail { struct { uint32_t Opcode; uint32_t Flags; uint32_t OperandStart; uint32_t OperandSize; } relax; struct { // The alignment to ensure, in bytes. Align Alignment; // The size of the integer (in bytes) of \p Value. uint8_t FillLen; // If true, fill with target-specific nop instructions. bool EmitNops; // The maximum number of bytes to emit; if the alignment // cannot be satisfied in this width then this fragment is ignored. unsigned MaxBytesToEmit; // Value to use for filling padding bytes. int64_t Fill; } align; struct { // True if this is a sleb128, false if uleb128. bool IsSigned; // The value this fragment should contain. const MCExpr *Value; } leb; // Used by .debug_frame and .debug_line to encode an address difference. struct { // The address difference between two labels. const MCExpr *AddrDelta; // The value of the difference between the two line numbers between two // .loc dwarf directives. int64_t LineDelta; } dwarf; struct { // This FRE describes unwind info at AddrDelta from function start. const MCExpr *AddrDelta; // Fragment that records how many bytes of AddrDelta to emit. MCFragment *FDEFragment; } sframe; } u{}; public: LLVM_ABI MCFragment(FragmentType Kind = MCFragment::FT_Data, bool HasInstructions = false); MCFragment(const MCFragment &) = delete; MCFragment &operator=(const MCFragment &) = delete; MCFragment *getNext() const { return Next; } FragmentType getKind() const { return Kind; } MCSection *getParent() const { return Parent; } void setParent(MCSection *Value) { Parent = Value; } LLVM_ABI const MCSymbol *getAtom() const; unsigned getLayoutOrder() const { return LayoutOrder; } void setLayoutOrder(unsigned Value) { LayoutOrder = Value; } /// Does this fragment have instructions emitted into it? By default /// this is false, but specific fragment types may set it to true. bool hasInstructions() const { return HasInstructions; } LLVM_ABI void dump() const; /// Retrieve the MCSubTargetInfo in effect when the instruction was encoded. /// Guaranteed to be non-null if hasInstructions() == true const MCSubtargetInfo *getSubtargetInfo() const { return STI; } /// Record that the fragment contains instructions with the MCSubtargetInfo in /// effect when the instruction was encoded. void setHasInstructions(const MCSubtargetInfo &STI) { HasInstructions = true; this->STI = &STI; } bool isLinkerRelaxable() const { return LinkerRelaxable; } void setLinkerRelaxable() { LinkerRelaxable = true; } bool getAllowAutoPadding() const { return AllowAutoPadding; } void setAllowAutoPadding(bool V) { AllowAutoPadding = V; } //== Content-related functions manage parent's storage using ContentStart and // ContentSize. MutableArrayRef getContents(); ArrayRef getContents() const; LLVM_ABI void setVarContents(ArrayRef Contents); void clearVarContents() { setVarContents({}); } MutableArrayRef getVarContents(); ArrayRef getVarContents() const; size_t getFixedSize() const { return FixedSize; } size_t getVarSize() const { return VarContentEnd - VarContentStart; } size_t getSize() const { return FixedSize + (VarContentEnd - VarContentStart); } //== Fixup-related functions manage parent's storage using FixupStart and // FixupSize. void clearFixups() { FixupEnd = FixupStart; } LLVM_ABI void addFixup(MCFixup Fixup); LLVM_ABI void appendFixups(ArrayRef Fixups); MutableArrayRef getFixups(); ArrayRef getFixups() const; // Source fixup offsets are relative to the variable part's start. // Stored fixup offsets are relative to the fixed part's start. LLVM_ABI void setVarFixups(ArrayRef Fixups); void clearVarFixups() { setVarFixups({}); } MutableArrayRef getVarFixups(); ArrayRef getVarFixups() const; //== FT_Relaxable functions unsigned getOpcode() const { assert(Kind == FT_Relaxable); return u.relax.Opcode; } ArrayRef getOperands() const; MCInst getInst() const; void setInst(const MCInst &Inst); //== FT_Align functions void makeAlign(Align Alignment, int64_t Fill, uint8_t FillLen, unsigned MaxBytesToEmit) { Kind = FT_Align; u.align.EmitNops = false; u.align.Alignment = Alignment; u.align.Fill = Fill; u.align.FillLen = FillLen; u.align.MaxBytesToEmit = MaxBytesToEmit; } Align getAlignment() const { assert(Kind == FT_Align); return u.align.Alignment; } int64_t getAlignFill() const { assert(Kind == FT_Align); return u.align.Fill; } uint8_t getAlignFillLen() const { assert(Kind == FT_Align); return u.align.FillLen; } unsigned getAlignMaxBytesToEmit() const { assert(Kind == FT_Align); return u.align.MaxBytesToEmit; } bool hasAlignEmitNops() const { assert(Kind == FT_Align); return u.align.EmitNops; } //== FT_LEB functions void makeLEB(bool IsSigned, const MCExpr *Value) { assert(Kind == FT_Data); Kind = MCFragment::FT_LEB; u.leb.IsSigned = IsSigned; u.leb.Value = Value; } const MCExpr &getLEBValue() const { assert(Kind == FT_LEB); return *u.leb.Value; } void setLEBValue(const MCExpr *Expr) { assert(Kind == FT_LEB); u.leb.Value = Expr; } bool isLEBSigned() const { assert(Kind == FT_LEB); return u.leb.IsSigned; } //== FT_DwarfFrame functions const MCExpr &getDwarfAddrDelta() const { assert(Kind == FT_Dwarf || Kind == FT_DwarfFrame); return *u.dwarf.AddrDelta; } void setDwarfAddrDelta(const MCExpr *E) { assert(Kind == FT_Dwarf || Kind == FT_DwarfFrame); u.dwarf.AddrDelta = E; } int64_t getDwarfLineDelta() const { assert(Kind == FT_Dwarf); return u.dwarf.LineDelta; } void setDwarfLineDelta(int64_t LineDelta) { assert(Kind == FT_Dwarf); u.dwarf.LineDelta = LineDelta; } //== FT_SFrame functions const MCExpr &getSFrameAddrDelta() const { assert(Kind == FT_SFrame); return *u.sframe.AddrDelta; } void setSFrameAddrDelta(const MCExpr *E) { assert(Kind == FT_SFrame); u.sframe.AddrDelta = E; } MCFragment *getSFrameFDE() const { assert(Kind == FT_SFrame); return u.sframe.FDEFragment; } void setSFrameFDE(MCFragment *F) { assert(Kind == FT_SFrame); u.sframe.FDEFragment = F; } }; // MCFragment subclasses do not use the fixed-size part or variable-size tail of // MCFragment. Instead, they encode content in a specialized way. class MCFillFragment : public MCFragment { uint8_t ValueSize; /// Value to use for filling bytes. uint64_t Value; /// The number of bytes to insert. const MCExpr &NumValues; /// Source location of the directive that this fragment was created for. SMLoc Loc; public: MCFillFragment(uint64_t Value, uint8_t VSize, const MCExpr &NumValues, SMLoc Loc) : MCFragment(FT_Fill), ValueSize(VSize), Value(Value), NumValues(NumValues), Loc(Loc) {} uint64_t getValue() const { return Value; } uint8_t getValueSize() const { return ValueSize; } const MCExpr &getNumValues() const { return NumValues; } SMLoc getLoc() const { return Loc; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Fill; } }; class MCNopsFragment : public MCFragment { /// The number of bytes to insert. int64_t Size; /// Maximum number of bytes allowed in each NOP instruction. int64_t ControlledNopLength; /// Source location of the directive that this fragment was created for. SMLoc Loc; public: MCNopsFragment(int64_t NumBytes, int64_t ControlledNopLength, SMLoc L, const MCSubtargetInfo &STI) : MCFragment(FT_Nops), Size(NumBytes), ControlledNopLength(ControlledNopLength), Loc(L) { this->STI = &STI; } int64_t getNumBytes() const { return Size; } int64_t getControlledNopLength() const { return ControlledNopLength; } SMLoc getLoc() const { return Loc; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Nops; } }; class MCOrgFragment : public MCFragment { /// Value to use for filling bytes. int8_t Value; /// The offset this fragment should start at. const MCExpr *Offset; /// Source location of the directive that this fragment was created for. SMLoc Loc; public: MCOrgFragment(const MCExpr &Offset, int8_t Value, SMLoc Loc) : MCFragment(FT_Org), Value(Value), Offset(&Offset), Loc(Loc) {} const MCExpr &getOffset() const { return *Offset; } uint8_t getValue() const { return Value; } SMLoc getLoc() const { return Loc; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Org; } }; /// Represents a symbol table index fragment. class MCSymbolIdFragment : public MCFragment { const MCSymbol *Sym; public: MCSymbolIdFragment(const MCSymbol *Sym) : MCFragment(FT_SymbolId), Sym(Sym) {} const MCSymbol *getSymbol() { return Sym; } const MCSymbol *getSymbol() const { return Sym; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_SymbolId; } }; /// Fragment representing the binary annotations produced by the /// .cv_inline_linetable directive. class MCCVInlineLineTableFragment : public MCFragment { unsigned SiteFuncId; unsigned StartFileId; unsigned StartLineNum; const MCSymbol *FnStartSym; const MCSymbol *FnEndSym; /// CodeViewContext has the real knowledge about this format, so let it access /// our members. friend class CodeViewContext; public: MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId, unsigned StartLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) : MCFragment(FT_CVInlineLines), SiteFuncId(SiteFuncId), StartFileId(StartFileId), StartLineNum(StartLineNum), FnStartSym(FnStartSym), FnEndSym(FnEndSym) {} const MCSymbol *getFnStartSym() const { return FnStartSym; } const MCSymbol *getFnEndSym() const { return FnEndSym; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_CVInlineLines; } }; /// Fragment representing the .cv_def_range directive. class MCCVDefRangeFragment : public MCFragment { ArrayRef> Ranges; StringRef FixedSizePortion; /// CodeViewContext has the real knowledge about this format, so let it access /// our members. friend class CodeViewContext; public: MCCVDefRangeFragment( ArrayRef> Ranges, StringRef FixedSizePortion) : MCFragment(FT_CVDefRange), Ranges(Ranges.begin(), Ranges.end()), FixedSizePortion(FixedSizePortion) {} ArrayRef> getRanges() const { return Ranges; } StringRef getFixedSizePortion() const { return FixedSizePortion; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_CVDefRange; } }; /// Represents required padding such that a particular other set of fragments /// does not cross a particular power-of-two boundary. The other fragments must /// follow this one within the same section. class MCBoundaryAlignFragment : public MCFragment { /// The alignment requirement of the branch to be aligned. Align AlignBoundary; /// The last fragment in the set of fragments to be aligned. const MCFragment *LastFragment = nullptr; /// The size of the fragment. The size is lazily set during relaxation, and /// is not meaningful before that. uint64_t Size = 0; public: MCBoundaryAlignFragment(Align AlignBoundary, const MCSubtargetInfo &STI) : MCFragment(FT_BoundaryAlign), AlignBoundary(AlignBoundary) { this->STI = &STI; } uint64_t getSize() const { return Size; } void setSize(uint64_t Value) { Size = Value; } Align getAlignment() const { return AlignBoundary; } void setAlignment(Align Value) { AlignBoundary = Value; } const MCFragment *getLastFragment() const { return LastFragment; } void setLastFragment(const MCFragment *F) { assert(!F || getParent() == F->getParent()); LastFragment = F; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_BoundaryAlign; } }; /// Instances of this class represent a uniqued identifier for a section in the /// current translation unit. The MCContext class uniques and creates these. class LLVM_ABI MCSection { public: friend MCAssembler; friend MCObjectStreamer; friend class MCFragment; static constexpr unsigned NonUniqueID = ~0U; struct iterator { MCFragment *F = nullptr; iterator() = default; explicit iterator(MCFragment *F) : F(F) {} MCFragment &operator*() const { return *F; } bool operator==(const iterator &O) const { return F == O.F; } bool operator!=(const iterator &O) const { return F != O.F; } iterator &operator++(); }; struct FragList { MCFragment *Head = nullptr; MCFragment *Tail = nullptr; }; private: // At parse time, this holds the fragment list of the current subsection. At // layout time, this holds the concatenated fragment lists of all subsections. FragList *CurFragList; // In many object file formats, this denotes the section symbol. In Mach-O, // this denotes an optional temporary label at the section start. MCSymbol *Begin; MCSymbol *End = nullptr; /// The alignment requirement of this section. Align Alignment; /// The section index in the assemblers section list. unsigned Ordinal = 0; // If not -1u, the first linker-relaxable fragment's order within the // subsection. When present, the offset between two locations crossing this // fragment may not be fully resolved. unsigned FirstLinkerRelaxable = -1u; /// Whether this section has had instructions emitted into it. bool HasInstructions : 1; bool IsRegistered : 1; bool IsText : 1; bool IsBss : 1; MCFragment DummyFragment; // Mapping from subsection number to fragment list. At layout time, the // subsection 0 list is replaced with concatenated fragments from all // subsections. SmallVector, 1> Subsections; // Content and fixup storage for fragments SmallVector ContentStorage; SmallVector FixupStorage; SmallVector MCOperandStorage; protected: // TODO Make Name private when possible. StringRef Name; MCSection(StringRef Name, bool IsText, bool IsBss, MCSymbol *Begin); public: MCSection(const MCSection &) = delete; MCSection &operator=(const MCSection &) = delete; StringRef getName() const { return Name; } bool isText() const { return IsText; } MCSymbol *getBeginSymbol() { return Begin; } const MCSymbol *getBeginSymbol() const { return const_cast(this)->getBeginSymbol(); } void setBeginSymbol(MCSymbol *Sym) { assert(!Begin); Begin = Sym; } MCSymbol *getEndSymbol(MCContext &Ctx); bool hasEnded() const; Align getAlign() const { return Alignment; } void setAlignment(Align Value) { Alignment = Value; } /// Makes sure that Alignment is at least MinAlignment. void ensureMinAlignment(Align MinAlignment) { if (Alignment < MinAlignment) Alignment = MinAlignment; } unsigned getOrdinal() const { return Ordinal; } void setOrdinal(unsigned Value) { Ordinal = Value; } bool hasInstructions() const { return HasInstructions; } void setHasInstructions(bool Value) { HasInstructions = Value; } bool isRegistered() const { return IsRegistered; } void setIsRegistered(bool Value) { IsRegistered = Value; } unsigned firstLinkerRelaxable() const { return FirstLinkerRelaxable; } bool isLinkerRelaxable() const { return FirstLinkerRelaxable != -1u; } void setFirstLinkerRelaxable(unsigned Order) { FirstLinkerRelaxable = Order; } MCFragment &getDummyFragment() { return DummyFragment; } FragList *curFragList() const { return CurFragList; } iterator begin() const { return iterator(CurFragList->Head); } iterator end() const { return {}; } void dump(DenseMap> *FragToSyms = nullptr) const; /// Check whether this section is "virtual", that is has no actual object /// file contents. bool isBssSection() const { return IsBss; } }; inline MutableArrayRef MCFragment::getContents() { return {reinterpret_cast(this + 1), FixedSize}; } inline ArrayRef MCFragment::getContents() const { return {reinterpret_cast(this + 1), FixedSize}; } inline MutableArrayRef MCFragment::getVarContents() { return MutableArrayRef(getParent()->ContentStorage) .slice(VarContentStart, VarContentEnd - VarContentStart); } inline ArrayRef MCFragment::getVarContents() const { return ArrayRef(getParent()->ContentStorage) .slice(VarContentStart, VarContentEnd - VarContentStart); } //== Fixup-related functions manage parent's storage using FixupStart and // FixupSize. inline MutableArrayRef MCFragment::getFixups() { return MutableArrayRef(getParent()->FixupStorage) .slice(FixupStart, FixupEnd - FixupStart); } inline ArrayRef MCFragment::getFixups() const { return ArrayRef(getParent()->FixupStorage) .slice(FixupStart, FixupEnd - FixupStart); } inline MutableArrayRef MCFragment::getVarFixups() { return MutableArrayRef(getParent()->FixupStorage) .slice(VarFixupStart, VarFixupSize); } inline ArrayRef MCFragment::getVarFixups() const { return ArrayRef(getParent()->FixupStorage).slice(VarFixupStart, VarFixupSize); } //== FT_Relaxable functions inline ArrayRef MCFragment::getOperands() const { assert(Kind == FT_Relaxable); return MutableArrayRef(getParent()->MCOperandStorage) .slice(u.relax.OperandStart, u.relax.OperandSize); } inline MCInst MCFragment::getInst() const { assert(Kind == FT_Relaxable); MCInst Inst; Inst.setOpcode(u.relax.Opcode); Inst.setFlags(u.relax.Flags); Inst.setOperands(ArrayRef(getParent()->MCOperandStorage) .slice(u.relax.OperandStart, u.relax.OperandSize)); return Inst; } inline void MCFragment::setInst(const MCInst &Inst) { assert(Kind == FT_Relaxable); u.relax.Opcode = Inst.getOpcode(); u.relax.Flags = Inst.getFlags(); auto &S = getParent()->MCOperandStorage; if (Inst.getNumOperands() > u.relax.OperandSize) { u.relax.OperandStart = S.size(); S.resize_for_overwrite(S.size() + Inst.getNumOperands()); } u.relax.OperandSize = Inst.getNumOperands(); llvm::copy(Inst, S.begin() + u.relax.OperandStart); } inline MCSection::iterator &MCSection::iterator::operator++() { F = F->Next; return *this; } } // end namespace llvm #endif // LLVM_MC_MCSECTION_H