Index: head/contrib/llvm/include/llvm/MC/MCFragment.h =================================================================== --- head/contrib/llvm/include/llvm/MC/MCFragment.h (revision 328595) +++ head/contrib/llvm/include/llvm/MC/MCFragment.h (revision 328596) @@ -1,659 +1,666 @@ //===- MCFragment.h - Fragment type hierarchy -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCFRAGMENT_H #define LLVM_MC_MCFRAGMENT_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/ilist_node.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCInst.h" #include "llvm/Support/Casting.h" #include "llvm/Support/SMLoc.h" #include #include namespace llvm { class MCSection; class MCSubtargetInfo; class MCSymbol; class MCFragment : public ilist_node_with_parent { friend class MCAsmLayout; public: enum FragmentType : uint8_t { FT_Align, FT_Data, FT_CompactEncodedInst, FT_Fill, FT_Relaxable, FT_Org, FT_Dwarf, FT_DwarfFrame, FT_LEB, FT_Padding, FT_SymbolId, FT_CVInlineLines, FT_CVDefRange, FT_Dummy }; private: FragmentType Kind; protected: bool HasInstructions; private: /// \brief Should this fragment be aligned to the end of a bundle? bool AlignToBundleEnd; uint8_t BundlePadding; /// LayoutOrder - The layout order of this fragment. unsigned LayoutOrder; /// The data for the section this fragment is in. MCSection *Parent; /// Atom - The atom this fragment is in, as represented by it's defining /// symbol. const MCSymbol *Atom; /// \name Assembler Backend Data /// @{ // // FIXME: This could all be kept private to the assembler implementation. /// Offset - The offset of this fragment in its section. This is ~0 until /// initialized. uint64_t Offset; /// @} protected: MCFragment(FragmentType Kind, bool HasInstructions, uint8_t BundlePadding, MCSection *Parent = nullptr); ~MCFragment(); public: MCFragment() = delete; MCFragment(const MCFragment &) = delete; MCFragment &operator=(const MCFragment &) = delete; /// Destroys the current fragment. /// /// This must be used instead of delete as MCFragment is non-virtual. /// This method will dispatch to the appropriate subclass. void destroy(); FragmentType getKind() const { return Kind; } MCSection *getParent() const { return Parent; } void setParent(MCSection *Value) { Parent = Value; } const MCSymbol *getAtom() const { return Atom; } void setAtom(const MCSymbol *Value) { Atom = Value; } unsigned getLayoutOrder() const { return LayoutOrder; } void setLayoutOrder(unsigned Value) { LayoutOrder = Value; } /// \brief 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; } /// \brief Should this fragment be placed at the end of an aligned bundle? bool alignToBundleEnd() const { return AlignToBundleEnd; } void setAlignToBundleEnd(bool V) { AlignToBundleEnd = V; } /// \brief Get the padding size that must be inserted before this fragment. /// Used for bundling. By default, no padding is inserted. /// Note that padding size is restricted to 8 bits. This is an optimization /// to reduce the amount of space used for each fragment. In practice, larger /// padding should never be required. uint8_t getBundlePadding() const { return BundlePadding; } /// \brief Set the padding size for this fragment. By default it's a no-op, /// and only some fragments have a meaningful implementation. void setBundlePadding(uint8_t N) { BundlePadding = N; } /// \brief Return true if given frgment has FT_Dummy type. bool isDummy() const { return Kind == FT_Dummy; } void dump() const; }; class MCDummyFragment : public MCFragment { public: explicit MCDummyFragment(MCSection *Sec) : MCFragment(FT_Dummy, false, 0, Sec) {} static bool classof(const MCFragment *F) { return F->getKind() == FT_Dummy; } }; /// Interface implemented by fragments that contain encoded instructions and/or /// data. /// class MCEncodedFragment : public MCFragment { protected: MCEncodedFragment(MCFragment::FragmentType FType, bool HasInstructions, MCSection *Sec) : MCFragment(FType, HasInstructions, 0, Sec) {} public: static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); switch (Kind) { default: return false; case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: case MCFragment::FT_Data: return true; } } }; /// Interface implemented by fragments that contain encoded instructions and/or /// data. /// template class MCEncodedFragmentWithContents : public MCEncodedFragment { SmallVector Contents; protected: MCEncodedFragmentWithContents(MCFragment::FragmentType FType, bool HasInstructions, MCSection *Sec) : MCEncodedFragment(FType, HasInstructions, Sec) {} public: SmallVectorImpl &getContents() { return Contents; } const SmallVectorImpl &getContents() const { return Contents; } }; /// Interface implemented by fragments that contain encoded instructions and/or /// data and also have fixups registered. /// template class MCEncodedFragmentWithFixups : public MCEncodedFragmentWithContents { /// Fixups - The list of fixups in this fragment. SmallVector Fixups; protected: MCEncodedFragmentWithFixups(MCFragment::FragmentType FType, bool HasInstructions, MCSection *Sec) : MCEncodedFragmentWithContents(FType, HasInstructions, Sec) {} public: using const_fixup_iterator = SmallVectorImpl::const_iterator; using fixup_iterator = SmallVectorImpl::iterator; SmallVectorImpl &getFixups() { return Fixups; } const SmallVectorImpl &getFixups() const { return Fixups; } fixup_iterator fixup_begin() { return Fixups.begin(); } const_fixup_iterator fixup_begin() const { return Fixups.begin(); } fixup_iterator fixup_end() { return Fixups.end(); } const_fixup_iterator fixup_end() const { return Fixups.end(); } static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data || Kind == MCFragment::FT_CVDefRange; } }; /// Fragment for data and encoded instructions. /// class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> { public: MCDataFragment(MCSection *Sec = nullptr) : MCEncodedFragmentWithFixups<32, 4>(FT_Data, false, Sec) {} void setHasInstructions(bool V) { HasInstructions = V; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Data; } }; /// This is a compact (memory-size-wise) fragment for holding an encoded /// instruction (non-relaxable) that has no fixups registered. When applicable, /// it can be used instead of MCDataFragment and lead to lower memory /// consumption. /// class MCCompactEncodedInstFragment : public MCEncodedFragmentWithContents<4> { public: MCCompactEncodedInstFragment(MCSection *Sec = nullptr) : MCEncodedFragmentWithContents(FT_CompactEncodedInst, true, Sec) { } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_CompactEncodedInst; } }; /// A relaxable fragment holds on to its MCInst, since it may need to be /// relaxed during the assembler layout and relaxation stage. /// class MCRelaxableFragment : public MCEncodedFragmentWithFixups<8, 1> { /// Inst - The instruction this is a fragment for. MCInst Inst; /// STI - The MCSubtargetInfo in effect when the instruction was encoded. const MCSubtargetInfo &STI; public: MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI, MCSection *Sec = nullptr) : MCEncodedFragmentWithFixups(FT_Relaxable, true, Sec), Inst(Inst), STI(STI) {} const MCInst &getInst() const { return Inst; } void setInst(const MCInst &Value) { Inst = Value; } const MCSubtargetInfo &getSubtargetInfo() { return STI; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Relaxable; } }; class MCAlignFragment : public MCFragment { /// Alignment - The alignment to ensure, in bytes. unsigned Alignment; /// EmitNops - Flag to indicate that (optimal) NOPs should be emitted instead /// of using the provided value. The exact interpretation of this flag is /// target dependent. bool EmitNops : 1; /// Value - Value to use for filling padding bytes. int64_t Value; /// ValueSize - The size of the integer (in bytes) of \p Value. unsigned ValueSize; /// MaxBytesToEmit - The maximum number of bytes to emit; if the alignment /// cannot be satisfied in this width then this fragment is ignored. unsigned MaxBytesToEmit; public: MCAlignFragment(unsigned Alignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit, MCSection *Sec = nullptr) : MCFragment(FT_Align, false, 0, Sec), Alignment(Alignment), EmitNops(false), Value(Value), ValueSize(ValueSize), MaxBytesToEmit(MaxBytesToEmit) {} /// \name Accessors /// @{ unsigned getAlignment() const { return Alignment; } int64_t getValue() const { return Value; } unsigned getValueSize() const { return ValueSize; } unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; } bool hasEmitNops() const { return EmitNops; } void setEmitNops(bool Value) { EmitNops = Value; } /// @} static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Align; } }; /// Fragment for adding required padding. /// This fragment is always inserted before an instruction, and holds that /// instruction as context information (as well as a mask of kinds) for /// determining the padding size. /// class MCPaddingFragment : public MCFragment { /// A mask containing all the kinds relevant to this fragment. i.e. the i'th /// bit will be set iff kind i is relevant to this fragment. uint64_t PaddingPoliciesMask; /// A boolean indicating if this fragment will actually hold padding. If its /// value is false, then this fragment serves only as a placeholder, /// containing data to assist other insertion point in their decision making. bool IsInsertionPoint; uint64_t Size; struct MCInstInfo { bool IsInitialized; MCInst Inst; /// A boolean indicating whether the instruction pointed by this fragment is /// a fixed size instruction or a relaxable instruction held by a /// MCRelaxableFragment. bool IsImmutableSizedInst; union { /// If the instruction is a fixed size instruction, hold its size. size_t InstSize; /// Otherwise, hold a pointer to the MCRelaxableFragment holding it. MCRelaxableFragment *InstFragment; }; }; MCInstInfo InstInfo; public: static const uint64_t PFK_None = UINT64_C(0); enum MCPaddingFragmentKind { // values 0-7 are reserved for future target independet values. FirstTargetPerfNopFragmentKind = 8, /// Limit range of target MCPerfNopFragment kinds to fit in uint64_t MaxTargetPerfNopFragmentKind = 63 }; MCPaddingFragment(MCSection *Sec = nullptr) : MCFragment(FT_Padding, false, 0, Sec), PaddingPoliciesMask(PFK_None), IsInsertionPoint(false), Size(UINT64_C(0)), InstInfo({false, MCInst(), false, {0}}) {} bool isInsertionPoint() const { return IsInsertionPoint; } void setAsInsertionPoint() { IsInsertionPoint = true; } uint64_t getPaddingPoliciesMask() const { return PaddingPoliciesMask; } void setPaddingPoliciesMask(uint64_t Value) { PaddingPoliciesMask = Value; } bool hasPaddingPolicy(uint64_t PolicyMask) const { assert(isPowerOf2_64(PolicyMask) && "Policy mask must contain exactly one policy"); return (getPaddingPoliciesMask() & PolicyMask) != PFK_None; } const MCInst &getInst() const { assert(isInstructionInitialized() && "Fragment has no instruction!"); return InstInfo.Inst; } size_t getInstSize() const { assert(isInstructionInitialized() && "Fragment has no instruction!"); if (InstInfo.IsImmutableSizedInst) return InstInfo.InstSize; assert(InstInfo.InstFragment != nullptr && "Must have a valid InstFragment to retrieve InstSize from"); return InstInfo.InstFragment->getContents().size(); } void setInstAndInstSize(const MCInst &Inst, size_t InstSize) { InstInfo.IsInitialized = true; InstInfo.IsImmutableSizedInst = true; InstInfo.Inst = Inst; InstInfo.InstSize = InstSize; } void setInstAndInstFragment(const MCInst &Inst, MCRelaxableFragment *InstFragment) { InstInfo.IsInitialized = true; InstInfo.IsImmutableSizedInst = false; InstInfo.Inst = Inst; InstInfo.InstFragment = InstFragment; } uint64_t getSize() const { return Size; } void setSize(uint64_t Value) { Size = Value; } bool isInstructionInitialized() const { return InstInfo.IsInitialized; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Padding; } }; class MCFillFragment : public MCFragment { /// Value to use for filling bytes. uint8_t Value; /// The number of bytes to insert. - uint64_t Size; + const MCExpr &Size; + /// Source location of the directive that this fragment was created for. + SMLoc Loc; + public: - MCFillFragment(uint8_t Value, uint64_t Size, MCSection *Sec = nullptr) - : MCFragment(FT_Fill, false, 0, Sec), Value(Value), Size(Size) {} + MCFillFragment(uint8_t Value, const MCExpr &Size, SMLoc Loc, + MCSection *Sec = nullptr) + : MCFragment(FT_Fill, false, 0, Sec), Value(Value), Size(Size), Loc(Loc) { + } uint8_t getValue() const { return Value; } - uint64_t getSize() const { return Size; } + const MCExpr &getSize() const { return Size; } + + SMLoc getLoc() const { return Loc; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Fill; } }; class MCOrgFragment : public MCFragment { /// Offset - The offset this fragment should start at. const MCExpr *Offset; /// Value - Value to use for filling bytes. int8_t Value; /// Loc - Source location of the directive that this fragment was created for. SMLoc Loc; public: MCOrgFragment(const MCExpr &Offset, int8_t Value, SMLoc Loc, MCSection *Sec = nullptr) : MCFragment(FT_Org, false, 0, Sec), Offset(&Offset), Value(Value), Loc(Loc) {} /// \name Accessors /// @{ 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; } }; class MCLEBFragment : public MCFragment { /// Value - The value this fragment should contain. const MCExpr *Value; /// IsSigned - True if this is a sleb128, false if uleb128. bool IsSigned; SmallString<8> Contents; public: MCLEBFragment(const MCExpr &Value_, bool IsSigned_, MCSection *Sec = nullptr) : MCFragment(FT_LEB, false, 0, Sec), Value(&Value_), IsSigned(IsSigned_) { Contents.push_back(0); } /// \name Accessors /// @{ const MCExpr &getValue() const { return *Value; } bool isSigned() const { return IsSigned; } SmallString<8> &getContents() { return Contents; } const SmallString<8> &getContents() const { return Contents; } /// @} static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_LEB; } }; class MCDwarfLineAddrFragment : public MCFragment { /// LineDelta - the value of the difference between the two line numbers /// between two .loc dwarf directives. int64_t LineDelta; /// AddrDelta - The expression for the difference of the two symbols that /// make up the address delta between two .loc dwarf directives. const MCExpr *AddrDelta; SmallString<8> Contents; public: MCDwarfLineAddrFragment(int64_t LineDelta, const MCExpr &AddrDelta, MCSection *Sec = nullptr) : MCFragment(FT_Dwarf, false, 0, Sec), LineDelta(LineDelta), AddrDelta(&AddrDelta) { Contents.push_back(0); } /// \name Accessors /// @{ int64_t getLineDelta() const { return LineDelta; } const MCExpr &getAddrDelta() const { return *AddrDelta; } SmallString<8> &getContents() { return Contents; } const SmallString<8> &getContents() const { return Contents; } /// @} static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Dwarf; } }; class MCDwarfCallFrameFragment : public MCFragment { /// AddrDelta - The expression for the difference of the two symbols that /// make up the address delta between two .cfi_* dwarf directives. const MCExpr *AddrDelta; SmallString<8> Contents; public: MCDwarfCallFrameFragment(const MCExpr &AddrDelta, MCSection *Sec = nullptr) : MCFragment(FT_DwarfFrame, false, 0, Sec), AddrDelta(&AddrDelta) { Contents.push_back(0); } /// \name Accessors /// @{ const MCExpr &getAddrDelta() const { return *AddrDelta; } SmallString<8> &getContents() { return Contents; } const SmallString<8> &getContents() const { return Contents; } /// @} static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_DwarfFrame; } }; /// Represents a symbol table index fragment. class MCSymbolIdFragment : public MCFragment { const MCSymbol *Sym; public: MCSymbolIdFragment(const MCSymbol *Sym, MCSection *Sec = nullptr) : MCFragment(FT_SymbolId, false, 0, Sec), Sym(Sym) {} /// \name Accessors /// @{ 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; SmallString<8> Contents; /// 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, MCSection *Sec = nullptr) : MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId), StartFileId(StartFileId), StartLineNum(StartLineNum), FnStartSym(FnStartSym), FnEndSym(FnEndSym) {} /// \name Accessors /// @{ const MCSymbol *getFnStartSym() const { return FnStartSym; } const MCSymbol *getFnEndSym() const { return FnEndSym; } SmallString<8> &getContents() { return Contents; } const SmallString<8> &getContents() const { return Contents; } /// @} static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_CVInlineLines; } }; /// Fragment representing the .cv_def_range directive. class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> { SmallVector, 2> Ranges; SmallString<32> FixedSizePortion; /// CodeViewContext has the real knowledge about this format, so let it access /// our members. friend class CodeViewContext; public: MCCVDefRangeFragment( ArrayRef> Ranges, StringRef FixedSizePortion, MCSection *Sec = nullptr) : MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false, Sec), Ranges(Ranges.begin(), Ranges.end()), FixedSizePortion(FixedSizePortion) {} /// \name Accessors /// @{ ArrayRef> getRanges() const { return Ranges; } StringRef getFixedSizePortion() const { return FixedSizePortion; } /// @} static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_CVDefRange; } }; } // end namespace llvm #endif // LLVM_MC_MCFRAGMENT_H Index: head/contrib/llvm/lib/MC/MCAssembler.cpp =================================================================== --- head/contrib/llvm/lib/MC/MCAssembler.cpp (revision 328595) +++ head/contrib/llvm/lib/MC/MCAssembler.cpp (revision 328596) @@ -1,988 +1,998 @@ //===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCAssembler.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCFragment.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include using namespace llvm; #define DEBUG_TYPE "assembler" namespace { namespace stats { STATISTIC(EmittedFragments, "Number of emitted assembler fragments - total"); STATISTIC(EmittedRelaxableFragments, "Number of emitted assembler fragments - relaxable"); STATISTIC(EmittedDataFragments, "Number of emitted assembler fragments - data"); STATISTIC(EmittedCompactEncodedInstFragments, "Number of emitted assembler fragments - compact encoded inst"); STATISTIC(EmittedAlignFragments, "Number of emitted assembler fragments - align"); STATISTIC(EmittedFillFragments, "Number of emitted assembler fragments - fill"); STATISTIC(EmittedOrgFragments, "Number of emitted assembler fragments - org"); STATISTIC(evaluateFixup, "Number of evaluated fixups"); STATISTIC(FragmentLayouts, "Number of fragment layouts"); STATISTIC(ObjectBytes, "Number of emitted object file bytes"); STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps"); STATISTIC(RelaxedInstructions, "Number of relaxed instructions"); STATISTIC(PaddingFragmentsRelaxations, "Number of Padding Fragments relaxations"); STATISTIC(PaddingFragmentsBytes, "Total size of all padding from adding Fragments"); } // end namespace stats } // end anonymous namespace // FIXME FIXME FIXME: There are number of places in this file where we convert // what is a 64-bit assembler value used for computation into a value in the // object file, which may truncate it. We should detect that truncation where // invalid and report errors back. /* *** */ MCAssembler::MCAssembler(MCContext &Context, MCAsmBackend &Backend, MCCodeEmitter &Emitter, MCObjectWriter &Writer) : Context(Context), Backend(Backend), Emitter(Emitter), Writer(Writer), BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" } MCAssembler::~MCAssembler() = default; void MCAssembler::reset() { Sections.clear(); Symbols.clear(); IndirectSymbols.clear(); DataRegions.clear(); LinkerOptions.clear(); FileNames.clear(); ThumbFuncs.clear(); BundleAlignSize = 0; RelaxAll = false; SubsectionsViaSymbols = false; IncrementalLinkerCompatible = false; ELFHeaderEFlags = 0; LOHContainer.reset(); VersionInfo.Major = 0; // reset objects owned by us getBackend().reset(); getEmitter().reset(); getWriter().reset(); getLOHContainer().reset(); } bool MCAssembler::registerSection(MCSection &Section) { if (Section.isRegistered()) return false; Sections.push_back(&Section); Section.setIsRegistered(true); return true; } bool MCAssembler::isThumbFunc(const MCSymbol *Symbol) const { if (ThumbFuncs.count(Symbol)) return true; if (!Symbol->isVariable()) return false; const MCExpr *Expr = Symbol->getVariableValue(); MCValue V; if (!Expr->evaluateAsRelocatable(V, nullptr, nullptr)) return false; if (V.getSymB() || V.getRefKind() != MCSymbolRefExpr::VK_None) return false; const MCSymbolRefExpr *Ref = V.getSymA(); if (!Ref) return false; if (Ref->getKind() != MCSymbolRefExpr::VK_None) return false; const MCSymbol &Sym = Ref->getSymbol(); if (!isThumbFunc(&Sym)) return false; ThumbFuncs.insert(Symbol); // Cache it. return true; } bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const { // Non-temporary labels should always be visible to the linker. if (!Symbol.isTemporary()) return true; // Absolute temporary labels are never visible. if (!Symbol.isInSection()) return false; if (Symbol.isUsedInReloc()) return true; return false; } const MCSymbol *MCAssembler::getAtom(const MCSymbol &S) const { // Linker visible symbols define atoms. if (isSymbolLinkerVisible(S)) return &S; // Absolute and undefined symbols have no defining atom. if (!S.isInSection()) return nullptr; // Non-linker visible symbols in sections which can't be atomized have no // defining atom. if (!getContext().getAsmInfo()->isSectionAtomizableBySymbols( *S.getFragment()->getParent())) return nullptr; // Otherwise, return the atom for the containing fragment. return S.getFragment()->getAtom(); } bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, uint64_t &Value) const { ++stats::evaluateFixup; // FIXME: This code has some duplication with recordRelocation. We should // probably merge the two into a single callback that tries to evaluate a // fixup and records a relocation if one is needed. // On error claim to have completely evaluated the fixup, to prevent any // further processing from being done. const MCExpr *Expr = Fixup.getValue(); MCContext &Ctx = getContext(); Value = 0; if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) { Ctx.reportError(Fixup.getLoc(), "expected relocatable expression"); return true; } if (const MCSymbolRefExpr *RefB = Target.getSymB()) { if (RefB->getKind() != MCSymbolRefExpr::VK_None) { Ctx.reportError(Fixup.getLoc(), "unsupported subtraction of qualified symbol"); return true; } } bool IsPCRel = Backend.getFixupKindInfo( Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; bool IsResolved; if (IsPCRel) { if (Target.getSymB()) { IsResolved = false; } else if (!Target.getSymA()) { IsResolved = false; } else { const MCSymbolRefExpr *A = Target.getSymA(); const MCSymbol &SA = A->getSymbol(); if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) { IsResolved = false; } else { IsResolved = getWriter().isSymbolRefDifferenceFullyResolvedImpl( *this, SA, *DF, false, true); } } } else { IsResolved = Target.isAbsolute(); } Value = Target.getConstant(); if (const MCSymbolRefExpr *A = Target.getSymA()) { const MCSymbol &Sym = A->getSymbol(); if (Sym.isDefined()) Value += Layout.getSymbolOffset(Sym); } if (const MCSymbolRefExpr *B = Target.getSymB()) { const MCSymbol &Sym = B->getSymbol(); if (Sym.isDefined()) Value -= Layout.getSymbolOffset(Sym); } bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; assert((ShouldAlignPC ? IsPCRel : true) && "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); if (IsPCRel) { uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset(); // A number of ARM fixups in Thumb mode require that the effective PC // address be determined as the 32-bit aligned version of the actual offset. if (ShouldAlignPC) Offset &= ~0x3; Value -= Offset; } // Let the backend force a relocation if needed. if (IsResolved && Backend.shouldForceRelocation(*this, Fixup, Target)) IsResolved = false; return IsResolved; } uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: return cast(F).getContents().size(); case MCFragment::FT_Relaxable: return cast(F).getContents().size(); case MCFragment::FT_CompactEncodedInst: return cast(F).getContents().size(); - case MCFragment::FT_Fill: - return cast(F).getSize(); + case MCFragment::FT_Fill: { + auto &FF = cast(F); + int64_t Size = 0; + if (!FF.getSize().evaluateAsAbsolute(Size, Layout)) + getContext().reportError(FF.getLoc(), + "expected assembly-time absolute expression"); + if (Size < 0) { + getContext().reportError(FF.getLoc(), "invalid number of bytes"); + return 0; + } + return Size; + } case MCFragment::FT_LEB: return cast(F).getContents().size(); case MCFragment::FT_Padding: return cast(F).getSize(); case MCFragment::FT_SymbolId: return 4; case MCFragment::FT_Align: { const MCAlignFragment &AF = cast(F); unsigned Offset = Layout.getFragmentOffset(&AF); unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); // If we are padding with nops, force the padding to be larger than the // minimum nop size. if (Size > 0 && AF.hasEmitNops()) { while (Size % getBackend().getMinimumNopSize()) Size += AF.getAlignment(); } if (Size > AF.getMaxBytesToEmit()) return 0; return Size; } case MCFragment::FT_Org: { const MCOrgFragment &OF = cast(F); MCValue Value; if (!OF.getOffset().evaluateAsValue(Value, Layout)) { getContext().reportError(OF.getLoc(), "expected assembly-time absolute expression"); return 0; } uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); int64_t TargetLocation = Value.getConstant(); if (const MCSymbolRefExpr *A = Value.getSymA()) { uint64_t Val; if (!Layout.getSymbolOffset(A->getSymbol(), Val)) { getContext().reportError(OF.getLoc(), "expected absolute expression"); return 0; } TargetLocation += Val; } int64_t Size = TargetLocation - FragmentOffset; if (Size < 0 || Size >= 0x40000000) { getContext().reportError( OF.getLoc(), "invalid .org offset '" + Twine(TargetLocation) + "' (at offset '" + Twine(FragmentOffset) + "')"); return 0; } return Size; } case MCFragment::FT_Dwarf: return cast(F).getContents().size(); case MCFragment::FT_DwarfFrame: return cast(F).getContents().size(); case MCFragment::FT_CVInlineLines: return cast(F).getContents().size(); case MCFragment::FT_CVDefRange: return cast(F).getContents().size(); case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } llvm_unreachable("invalid fragment kind"); } void MCAsmLayout::layoutFragment(MCFragment *F) { MCFragment *Prev = F->getPrevNode(); // We should never try to recompute something which is valid. assert(!isFragmentValid(F) && "Attempt to recompute a valid fragment!"); // We should never try to compute the fragment layout if its predecessor // isn't valid. assert((!Prev || isFragmentValid(Prev)) && "Attempt to compute fragment before its predecessor!"); ++stats::FragmentLayouts; // Compute fragment offset and size. if (Prev) F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev); else F->Offset = 0; LastValidFragment[F->getParent()] = F; // If bundling is enabled and this fragment has instructions in it, it has to // obey the bundling restrictions. With padding, we'll have: // // // BundlePadding // ||| // ------------------------------------- // Prev |##########| F | // ------------------------------------- // ^ // | // F->Offset // // The fragment's offset will point to after the padding, and its computed // size won't include the padding. // // When the -mc-relax-all flag is used, we optimize bundling by writting the // padding directly into fragments when the instructions are emitted inside // the streamer. When the fragment is larger than the bundle size, we need to // ensure that it's bundle aligned. This means that if we end up with // multiple fragments, we must emit bundle padding between fragments. // // ".align N" is an example of a directive that introduces multiple // fragments. We could add a special case to handle ".align N" by emitting // within-fragment padding (which would produce less padding when N is less // than the bundle size), but for now we don't. // if (Assembler.isBundlingEnabled() && F->hasInstructions()) { assert(isa(F) && "Only MCEncodedFragment implementations have instructions"); uint64_t FSize = Assembler.computeFragmentSize(*this, *F); if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize()) report_fatal_error("Fragment can't be larger than a bundle size"); uint64_t RequiredBundlePadding = computeBundlePadding(Assembler, F, F->Offset, FSize); if (RequiredBundlePadding > UINT8_MAX) report_fatal_error("Padding cannot exceed 255 bytes"); F->setBundlePadding(static_cast(RequiredBundlePadding)); F->Offset += RequiredBundlePadding; } } void MCAssembler::registerSymbol(const MCSymbol &Symbol, bool *Created) { bool New = !Symbol.isRegistered(); if (Created) *Created = New; if (New) { Symbol.setIsRegistered(true); Symbols.push_back(&Symbol); } } void MCAssembler::writeFragmentPadding(const MCFragment &F, uint64_t FSize, MCObjectWriter *OW) const { // Should NOP padding be written out before this fragment? unsigned BundlePadding = F.getBundlePadding(); if (BundlePadding > 0) { assert(isBundlingEnabled() && "Writing bundle padding with disabled bundling"); assert(F.hasInstructions() && "Writing bundle padding for a fragment without instructions"); unsigned TotalLength = BundlePadding + static_cast(FSize); if (F.alignToBundleEnd() && TotalLength > getBundleAlignSize()) { // If the padding itself crosses a bundle boundary, it must be emitted // in 2 pieces, since even nop instructions must not cross boundaries. // v--------------v <- BundleAlignSize // v---------v <- BundlePadding // ---------------------------- // | Prev |####|####| F | // ---------------------------- // ^-------------------^ <- TotalLength unsigned DistanceToBoundary = TotalLength - getBundleAlignSize(); if (!getBackend().writeNopData(DistanceToBoundary, OW)) report_fatal_error("unable to write NOP sequence of " + Twine(DistanceToBoundary) + " bytes"); BundlePadding -= DistanceToBoundary; } if (!getBackend().writeNopData(BundlePadding, OW)) report_fatal_error("unable to write NOP sequence of " + Twine(BundlePadding) + " bytes"); } } /// \brief Write the fragment \p F to the output file. static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment &F) { MCObjectWriter *OW = &Asm.getWriter(); // FIXME: Embed in fragments instead? uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); Asm.writeFragmentPadding(F, FragmentSize, OW); // This variable (and its dummy usage) is to participate in the assert at // the end of the function. uint64_t Start = OW->getStream().tell(); (void) Start; ++stats::EmittedFragments; switch (F.getKind()) { case MCFragment::FT_Align: { ++stats::EmittedAlignFragments; const MCAlignFragment &AF = cast(F); assert(AF.getValueSize() && "Invalid virtual align in concrete fragment!"); uint64_t Count = FragmentSize / AF.getValueSize(); // FIXME: This error shouldn't actually occur (the front end should emit // multiple .align directives to enforce the semantics it wants), but is // severe enough that we want to report it. How to handle this? if (Count * AF.getValueSize() != FragmentSize) report_fatal_error("undefined .align directive, value size '" + Twine(AF.getValueSize()) + "' is not a divisor of padding size '" + Twine(FragmentSize) + "'"); // See if we are aligning with nops, and if so do that first to try to fill // the Count bytes. Then if that did not fill any bytes or there are any // bytes left to fill use the Value and ValueSize to fill the rest. // If we are aligning with nops, ask that target to emit the right data. if (AF.hasEmitNops()) { if (!Asm.getBackend().writeNopData(Count, OW)) report_fatal_error("unable to write nop sequence of " + Twine(Count) + " bytes"); break; } // Otherwise, write out in multiples of the value size. for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: llvm_unreachable("Invalid size!"); case 1: OW->write8 (uint8_t (AF.getValue())); break; case 2: OW->write16(uint16_t(AF.getValue())); break; case 4: OW->write32(uint32_t(AF.getValue())); break; case 8: OW->write64(uint64_t(AF.getValue())); break; } } break; } case MCFragment::FT_Data: ++stats::EmittedDataFragments; OW->writeBytes(cast(F).getContents()); break; case MCFragment::FT_Relaxable: ++stats::EmittedRelaxableFragments; OW->writeBytes(cast(F).getContents()); break; case MCFragment::FT_CompactEncodedInst: ++stats::EmittedCompactEncodedInstFragments; OW->writeBytes(cast(F).getContents()); break; case MCFragment::FT_Fill: { ++stats::EmittedFillFragments; const MCFillFragment &FF = cast(F); uint8_t V = FF.getValue(); const unsigned MaxChunkSize = 16; char Data[MaxChunkSize]; memcpy(Data, &V, 1); for (unsigned I = 1; I < MaxChunkSize; ++I) Data[I] = Data[0]; - uint64_t Size = FF.getSize(); + uint64_t Size = FragmentSize; for (unsigned ChunkSize = MaxChunkSize; ChunkSize; ChunkSize /= 2) { StringRef Ref(Data, ChunkSize); for (uint64_t I = 0, E = Size / ChunkSize; I != E; ++I) OW->writeBytes(Ref); Size = Size % ChunkSize; } break; } case MCFragment::FT_LEB: { const MCLEBFragment &LF = cast(F); OW->writeBytes(LF.getContents()); break; } case MCFragment::FT_Padding: { if (!Asm.getBackend().writeNopData(FragmentSize, OW)) report_fatal_error("unable to write nop sequence of " + Twine(FragmentSize) + " bytes"); break; } case MCFragment::FT_SymbolId: { const MCSymbolIdFragment &SF = cast(F); OW->write32(SF.getSymbol()->getIndex()); break; } case MCFragment::FT_Org: { ++stats::EmittedOrgFragments; const MCOrgFragment &OF = cast(F); for (uint64_t i = 0, e = FragmentSize; i != e; ++i) OW->write8(uint8_t(OF.getValue())); break; } case MCFragment::FT_Dwarf: { const MCDwarfLineAddrFragment &OF = cast(F); OW->writeBytes(OF.getContents()); break; } case MCFragment::FT_DwarfFrame: { const MCDwarfCallFrameFragment &CF = cast(F); OW->writeBytes(CF.getContents()); break; } case MCFragment::FT_CVInlineLines: { const auto &OF = cast(F); OW->writeBytes(OF.getContents()); break; } case MCFragment::FT_CVDefRange: { const auto &DRF = cast(F); OW->writeBytes(DRF.getContents()); break; } case MCFragment::FT_Dummy: llvm_unreachable("Should not have been added"); } assert(OW->getStream().tell() - Start == FragmentSize && "The stream should advance by fragment size"); } void MCAssembler::writeSectionData(const MCSection *Sec, const MCAsmLayout &Layout) const { // Ignore virtual sections. if (Sec->isVirtualSection()) { assert(Layout.getSectionFileSize(Sec) == 0 && "Invalid size for section!"); // Check that contents are only things legal inside a virtual section. for (const MCFragment &F : *Sec) { switch (F.getKind()) { default: llvm_unreachable("Invalid fragment in virtual section!"); case MCFragment::FT_Data: { // Check that we aren't trying to write a non-zero contents (or fixups) // into a virtual section. This is to support clients which use standard // directives to fill the contents of virtual sections. const MCDataFragment &DF = cast(F); if (DF.fixup_begin() != DF.fixup_end()) report_fatal_error("cannot have fixups in virtual section!"); for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i) if (DF.getContents()[i]) { if (auto *ELFSec = dyn_cast(Sec)) report_fatal_error("non-zero initializer found in section '" + ELFSec->getSectionName() + "'"); else report_fatal_error("non-zero initializer found in virtual section"); } break; } case MCFragment::FT_Align: // Check that we aren't trying to write a non-zero value into a virtual // section. assert((cast(F).getValueSize() == 0 || cast(F).getValue() == 0) && "Invalid align in virtual section!"); break; case MCFragment::FT_Fill: assert((cast(F).getValue() == 0) && "Invalid fill in virtual section!"); break; } } return; } uint64_t Start = getWriter().getStream().tell(); (void)Start; for (const MCFragment &F : *Sec) writeFragment(*this, Layout, F); assert(getWriter().getStream().tell() - Start == Layout.getSectionAddressSize(Sec)); } std::tuple MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F, const MCFixup &Fixup) { // Evaluate the fixup. MCValue Target; uint64_t FixedValue; bool IsResolved = evaluateFixup(Layout, Fixup, &F, Target, FixedValue); if (!IsResolved) { // The fixup was unresolved, we need a relocation. Inform the object // writer of the relocation, and give it an opportunity to adjust the // fixup value if need be. getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); } return std::make_tuple(Target, FixedValue, IsResolved); } void MCAssembler::layout(MCAsmLayout &Layout) { DEBUG_WITH_TYPE("mc-dump", { errs() << "assembler backend - pre-layout\n--\n"; dump(); }); // Create dummy fragments and assign section ordinals. unsigned SectionIndex = 0; for (MCSection &Sec : *this) { // Create dummy fragments to eliminate any empty sections, this simplifies // layout. if (Sec.getFragmentList().empty()) new MCDataFragment(&Sec); Sec.setOrdinal(SectionIndex++); } // Assign layout order indices to sections and fragments. for (unsigned i = 0, e = Layout.getSectionOrder().size(); i != e; ++i) { MCSection *Sec = Layout.getSectionOrder()[i]; Sec->setLayoutOrder(i); unsigned FragmentIndex = 0; for (MCFragment &Frag : *Sec) Frag.setLayoutOrder(FragmentIndex++); } // Layout until everything fits. while (layoutOnce(Layout)) if (getContext().hadError()) return; DEBUG_WITH_TYPE("mc-dump", { errs() << "assembler backend - post-relaxation\n--\n"; dump(); }); // Finalize the layout, including fragment lowering. finishLayout(Layout); DEBUG_WITH_TYPE("mc-dump", { errs() << "assembler backend - final-layout\n--\n"; dump(); }); // Allow the object writer a chance to perform post-layout binding (for // example, to set the index fields in the symbol data). getWriter().executePostLayoutBinding(*this, Layout); // Evaluate and apply the fixups, generating relocation entries as necessary. for (MCSection &Sec : *this) { for (MCFragment &Frag : Sec) { // Data and relaxable fragments both have fixups. So only process // those here. // FIXME: Is there a better way to do this? MCEncodedFragmentWithFixups // being templated makes this tricky. if (isa(&Frag) && isa(&Frag)) continue; if (!isa(&Frag) && !isa(&Frag)) continue; ArrayRef Fixups; MutableArrayRef Contents; if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); } else if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); } else if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); } else llvm_unreachable("Unknown fragment with fixups!"); for (const MCFixup &Fixup : Fixups) { uint64_t FixedValue; bool IsResolved; MCValue Target; std::tie(Target, FixedValue, IsResolved) = handleFixup(Layout, Frag, Fixup); getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue, IsResolved); } } } } void MCAssembler::Finish() { // Create the layout object. MCAsmLayout Layout(*this); layout(Layout); raw_ostream &OS = getWriter().getStream(); uint64_t StartOffset = OS.tell(); // Write the object file. getWriter().writeObject(*this, Layout); stats::ObjectBytes += OS.tell() - StartOffset; } bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { MCValue Target; uint64_t Value; bool Resolved = evaluateFixup(Layout, Fixup, DF, Target, Value); if (Target.getSymA() && Target.getSymA()->getKind() == MCSymbolRefExpr::VK_X86_ABS8 && Fixup.getKind() == FK_Data_1) return false; return getBackend().fixupNeedsRelaxationAdvanced(Fixup, Resolved, Value, DF, Layout); } bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F, const MCAsmLayout &Layout) const { // If this inst doesn't ever need relaxation, ignore it. This occurs when we // are intentionally pushing out inst fragments, or because we relaxed a // previous instruction to one that doesn't need relaxation. if (!getBackend().mayNeedRelaxation(F->getInst())) return false; for (const MCFixup &Fixup : F->getFixups()) if (fixupNeedsRelaxation(Fixup, F, Layout)) return true; return false; } bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, MCRelaxableFragment &F) { if (!fragmentNeedsRelaxation(&F, Layout)) return false; ++stats::RelaxedInstructions; // FIXME-PERF: We could immediately lower out instructions if we can tell // they are fully resolved, to avoid retesting on later passes. // Relax the fragment. MCInst Relaxed; getBackend().relaxInstruction(F.getInst(), F.getSubtargetInfo(), Relaxed); // Encode the new instruction. // // FIXME-PERF: If it matters, we could let the target do this. It can // probably do so more efficiently in many cases. SmallVector Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, F.getSubtargetInfo()); // Update the fragment. F.setInst(Relaxed); F.getContents() = Code; F.getFixups() = Fixups; return true; } bool MCAssembler::relaxPaddingFragment(MCAsmLayout &Layout, MCPaddingFragment &PF) { uint64_t OldSize = PF.getSize(); if (!getBackend().relaxFragment(&PF, Layout)) return false; uint64_t NewSize = PF.getSize(); ++stats::PaddingFragmentsRelaxations; stats::PaddingFragmentsBytes += NewSize; stats::PaddingFragmentsBytes -= OldSize; return true; } bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { uint64_t OldSize = LF.getContents().size(); int64_t Value; bool Abs = LF.getValue().evaluateKnownAbsolute(Value, Layout); if (!Abs) report_fatal_error("sleb128 and uleb128 expressions must be absolute"); SmallString<8> &Data = LF.getContents(); Data.clear(); raw_svector_ostream OSE(Data); if (LF.isSigned()) encodeSLEB128(Value, OSE); else encodeULEB128(Value, OSE); return OldSize != LF.getContents().size(); } bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF) { MCContext &Context = Layout.getAssembler().getContext(); uint64_t OldSize = DF.getContents().size(); int64_t AddrDelta; bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); assert(Abs && "We created a line delta with an invalid expression"); (void) Abs; int64_t LineDelta; LineDelta = DF.getLineDelta(); SmallString<8> &Data = DF.getContents(); Data.clear(); raw_svector_ostream OSE(Data); MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, AddrDelta, OSE); return OldSize != Data.size(); } bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout, MCDwarfCallFrameFragment &DF) { MCContext &Context = Layout.getAssembler().getContext(); uint64_t OldSize = DF.getContents().size(); int64_t AddrDelta; bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); assert(Abs && "We created call frame with an invalid expression"); (void) Abs; SmallString<8> &Data = DF.getContents(); Data.clear(); raw_svector_ostream OSE(Data); MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); return OldSize != Data.size(); } bool MCAssembler::relaxCVInlineLineTable(MCAsmLayout &Layout, MCCVInlineLineTableFragment &F) { unsigned OldSize = F.getContents().size(); getContext().getCVContext().encodeInlineLineTable(Layout, F); return OldSize != F.getContents().size(); } bool MCAssembler::relaxCVDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F) { unsigned OldSize = F.getContents().size(); getContext().getCVContext().encodeDefRange(Layout, F); return OldSize != F.getContents().size(); } bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) { // Holds the first fragment which needed relaxing during this layout. It will // remain NULL if none were relaxed. // When a fragment is relaxed, all the fragments following it should get // invalidated because their offset is going to change. MCFragment *FirstRelaxedFragment = nullptr; // Attempt to relax all the fragments in the section. for (MCSection::iterator I = Sec.begin(), IE = Sec.end(); I != IE; ++I) { // Check if this is a fragment that needs relaxation. bool RelaxedFrag = false; switch(I->getKind()) { default: break; case MCFragment::FT_Relaxable: assert(!getRelaxAll() && "Did not expect a MCRelaxableFragment in RelaxAll mode"); RelaxedFrag = relaxInstruction(Layout, *cast(I)); break; case MCFragment::FT_Dwarf: RelaxedFrag = relaxDwarfLineAddr(Layout, *cast(I)); break; case MCFragment::FT_DwarfFrame: RelaxedFrag = relaxDwarfCallFrameFragment(Layout, *cast(I)); break; case MCFragment::FT_LEB: RelaxedFrag = relaxLEB(Layout, *cast(I)); break; case MCFragment::FT_Padding: RelaxedFrag = relaxPaddingFragment(Layout, *cast(I)); break; case MCFragment::FT_CVInlineLines: RelaxedFrag = relaxCVInlineLineTable(Layout, *cast(I)); break; case MCFragment::FT_CVDefRange: RelaxedFrag = relaxCVDefRange(Layout, *cast(I)); break; } if (RelaxedFrag && !FirstRelaxedFragment) FirstRelaxedFragment = &*I; } if (FirstRelaxedFragment) { Layout.invalidateFragmentsFrom(FirstRelaxedFragment); return true; } return false; } bool MCAssembler::layoutOnce(MCAsmLayout &Layout) { ++stats::RelaxationSteps; bool WasRelaxed = false; for (iterator it = begin(), ie = end(); it != ie; ++it) { MCSection &Sec = *it; while (layoutSectionOnce(Layout, Sec)) WasRelaxed = true; } return WasRelaxed; } void MCAssembler::finishLayout(MCAsmLayout &Layout) { // The layout is done. Mark every fragment as valid. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { MCSection &Section = *Layout.getSectionOrder()[i]; Layout.getFragmentOffset(&*Section.rbegin()); computeFragmentSize(Layout, *Section.rbegin()); } getBackend().finishLayout(*this, Layout); } Index: head/contrib/llvm/lib/MC/MCObjectStreamer.cpp =================================================================== --- head/contrib/llvm/lib/MC/MCObjectStreamer.cpp (revision 328595) +++ head/contrib/llvm/lib/MC/MCObjectStreamer.cpp (revision 328596) @@ -1,632 +1,621 @@ //===- lib/MC/MCObjectStreamer.cpp - Object File MCStreamer Interface -----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCObjectStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SourceMgr.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, std::unique_ptr TAB, raw_pwrite_stream &OS, std::unique_ptr Emitter) : MCStreamer(Context), ObjectWriter(TAB->createObjectWriter(OS)), TAB(std::move(TAB)), Emitter(std::move(Emitter)), Assembler(llvm::make_unique(Context, *this->TAB, *this->Emitter, *ObjectWriter)), EmitEHFrame(true), EmitDebugFrame(false) {} MCObjectStreamer::~MCObjectStreamer() {} void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { if (PendingLabels.empty()) return; if (!F) { F = new MCDataFragment(); MCSection *CurSection = getCurrentSectionOnly(); CurSection->getFragmentList().insert(CurInsertionPoint, F); F->setParent(CurSection); } for (MCSymbol *Sym : PendingLabels) { Sym->setFragment(F); Sym->setOffset(FOffset); } PendingLabels.clear(); } void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) { // If not assigned to the same (valid) fragment, fallback. if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || Hi->isVariable() || Lo->isVariable()) { MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size); return; } EmitIntValue(Hi->getOffset() - Lo->getOffset(), Size); } void MCObjectStreamer::reset() { if (Assembler) Assembler->reset(); CurInsertionPoint = MCSection::iterator(); EmitEHFrame = true; EmitDebugFrame = false; PendingLabels.clear(); MCStreamer::reset(); } void MCObjectStreamer::EmitFrames(MCAsmBackend *MAB) { if (!getNumFrameInfos()) return; if (EmitEHFrame) MCDwarfFrameEmitter::Emit(*this, MAB, true); if (EmitDebugFrame) MCDwarfFrameEmitter::Emit(*this, MAB, false); } MCFragment *MCObjectStreamer::getCurrentFragment() const { assert(getCurrentSectionOnly() && "No current section!"); if (CurInsertionPoint != getCurrentSectionOnly()->getFragmentList().begin()) return &*std::prev(CurInsertionPoint); return nullptr; } MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() { MCDataFragment *F = dyn_cast_or_null(getCurrentFragment()); // When bundling is enabled, we don't want to add data to a fragment that // already has instructions (see MCELFStreamer::EmitInstToData for details) if (!F || (Assembler->isBundlingEnabled() && !Assembler->getRelaxAll() && F->hasInstructions())) { F = new MCDataFragment(); insert(F); } return F; } MCPaddingFragment *MCObjectStreamer::getOrCreatePaddingFragment() { MCPaddingFragment *F = dyn_cast_or_null(getCurrentFragment()); if (!F) { F = new MCPaddingFragment(); insert(F); } return F; } void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) { Assembler->registerSymbol(Sym); } void MCObjectStreamer::EmitCFISections(bool EH, bool Debug) { MCStreamer::EmitCFISections(EH, Debug); EmitEHFrame = EH; EmitDebugFrame = Debug; } void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) { MCStreamer::EmitValueImpl(Value, Size, Loc); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); MCCVLineEntry::Make(this); MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); // Avoid fixups when possible. int64_t AbsValue; if (Value->evaluateAsAbsolute(AbsValue, getAssembler())) { if (!isUIntN(8 * Size, AbsValue) && !isIntN(8 * Size, AbsValue)) { getContext().reportError( Loc, "value evaluated as " + Twine(AbsValue) + " is out of range."); return; } EmitIntValue(AbsValue, Size); return; } DF->getFixups().push_back( MCFixup::create(DF->getContents().size(), Value, MCFixup::getKindForSize(Size, false), Loc)); DF->getContents().resize(DF->getContents().size() + Size, 0); } MCSymbol *MCObjectStreamer::EmitCFILabel() { MCSymbol *Label = getContext().createTempSymbol("cfi", true); EmitLabel(Label); return Label; } void MCObjectStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { // We need to create a local symbol to avoid relocations. Frame.Begin = getContext().createTempSymbol(); EmitLabel(Frame.Begin); } void MCObjectStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { Frame.End = getContext().createTempSymbol(); EmitLabel(Frame.End); } void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) { MCStreamer::EmitLabel(Symbol, Loc); getAssembler().registerSymbol(*Symbol); // If there is a current fragment, mark the symbol as pointing into it. // Otherwise queue the label and set its fragment pointer when we emit the // next fragment. auto *F = dyn_cast_or_null(getCurrentFragment()); if (F && !(getAssembler().isBundlingEnabled() && getAssembler().getRelaxAll())) { Symbol->setFragment(F); Symbol->setOffset(F->getContents().size()); } else { PendingLabels.push_back(Symbol); } } void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) { MCStreamer::EmitLabel(Symbol, Loc); getAssembler().registerSymbol(*Symbol); auto *DF = dyn_cast_or_null(F); if (DF) Symbol->setFragment(F); else PendingLabels.push_back(Symbol); } void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { int64_t IntValue; if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { EmitULEB128IntValue(IntValue); return; } insert(new MCLEBFragment(*Value, false)); } void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value) { int64_t IntValue; if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { EmitSLEB128IntValue(IntValue); return; } insert(new MCLEBFragment(*Value, true)); } void MCObjectStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { report_fatal_error("This file format doesn't support weak aliases."); } void MCObjectStreamer::ChangeSection(MCSection *Section, const MCExpr *Subsection) { changeSectionImpl(Section, Subsection); } bool MCObjectStreamer::changeSectionImpl(MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); flushPendingLabels(nullptr); getContext().clearDwarfLocSeen(); bool Created = getAssembler().registerSection(*Section); int64_t IntSubsection = 0; if (Subsection && !Subsection->evaluateAsAbsolute(IntSubsection, getAssembler())) report_fatal_error("Cannot evaluate subsection number"); if (IntSubsection < 0 || IntSubsection > 8192) report_fatal_error("Subsection number out of range"); CurInsertionPoint = Section->getSubsectionInsertionPoint(unsigned(IntSubsection)); return Created; } void MCObjectStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { getAssembler().registerSymbol(*Symbol); MCStreamer::EmitAssignment(Symbol, Value); } bool MCObjectStreamer::mayHaveInstructions(MCSection &Sec) const { return Sec.hasInstructions(); } void MCObjectStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, bool) { getAssembler().getBackend().handleCodePaddingInstructionBegin(Inst); EmitInstructionImpl(Inst, STI); getAssembler().getBackend().handleCodePaddingInstructionEnd(Inst); } void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst, const MCSubtargetInfo &STI) { MCStreamer::EmitInstruction(Inst, STI); MCSection *Sec = getCurrentSectionOnly(); Sec->setHasInstructions(true); // Now that a machine instruction has been assembled into this section, make // a line entry for any .loc directive that has been seen. MCCVLineEntry::Make(this); MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); // If this instruction doesn't need relaxation, just emit it as data. MCAssembler &Assembler = getAssembler(); if (!Assembler.getBackend().mayNeedRelaxation(Inst)) { EmitInstToData(Inst, STI); return; } // Otherwise, relax and emit it as data if either: // - The RelaxAll flag was passed // - Bundling is enabled and this instruction is inside a bundle-locked // group. We want to emit all such instructions into the same data // fragment. if (Assembler.getRelaxAll() || (Assembler.isBundlingEnabled() && Sec->isBundleLocked())) { MCInst Relaxed; getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed); while (getAssembler().getBackend().mayNeedRelaxation(Relaxed)) getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed); EmitInstToData(Relaxed, STI); return; } // Otherwise emit to a separate fragment. EmitInstToFragment(Inst, STI); } void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &STI) { if (getAssembler().getRelaxAll() && getAssembler().isBundlingEnabled()) llvm_unreachable("All instructions should have already been relaxed"); // Always create a new, separate fragment here, because its size can change // during relaxation. MCRelaxableFragment *IF = new MCRelaxableFragment(Inst, STI); insert(IF); SmallString<128> Code; raw_svector_ostream VecOS(Code); getAssembler().getEmitter().encodeInstruction(Inst, VecOS, IF->getFixups(), STI); IF->getContents().append(Code.begin(), Code.end()); } #ifndef NDEBUG static const char *const BundlingNotImplementedMsg = "Aligned bundling is not implemented for this object format"; #endif void MCObjectStreamer::EmitBundleAlignMode(unsigned AlignPow2) { llvm_unreachable(BundlingNotImplementedMsg); } void MCObjectStreamer::EmitBundleLock(bool AlignToEnd) { llvm_unreachable(BundlingNotImplementedMsg); } void MCObjectStreamer::EmitBundleUnlock() { llvm_unreachable(BundlingNotImplementedMsg); } void MCObjectStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags, unsigned Isa, unsigned Discriminator, StringRef FileName) { // In case we see two .loc directives in a row, make sure the // first one gets a line entry. MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, Isa, Discriminator, FileName); } static const MCExpr *buildSymbolDiff(MCObjectStreamer &OS, const MCSymbol *A, const MCSymbol *B) { MCContext &Context = OS.getContext(); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context); const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context); const MCExpr *AddrDelta = MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context); return AddrDelta; } static void emitDwarfSetLineAddr(MCObjectStreamer &OS, MCDwarfLineTableParams Params, int64_t LineDelta, const MCSymbol *Label, int PointerSize) { // emit the sequence to set the address OS.EmitIntValue(dwarf::DW_LNS_extended_op, 1); OS.EmitULEB128IntValue(PointerSize + 1); OS.EmitIntValue(dwarf::DW_LNE_set_address, 1); OS.EmitSymbolValue(Label, PointerSize); // emit the sequence for the LineDelta (from 1) and a zero address delta. MCDwarfLineAddr::Emit(&OS, Params, LineDelta, 0); } void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel, const MCSymbol *Label, unsigned PointerSize) { if (!LastLabel) { emitDwarfSetLineAddr(*this, Assembler->getDWARFLinetableParams(), LineDelta, Label, PointerSize); return; } const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel); int64_t Res; if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) { MCDwarfLineAddr::Emit(this, Assembler->getDWARFLinetableParams(), LineDelta, Res); return; } insert(new MCDwarfLineAddrFragment(LineDelta, *AddrDelta)); } void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, const MCSymbol *Label) { const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel); int64_t Res; if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) { MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res); return; } insert(new MCDwarfCallFrameFragment(*AddrDelta)); } void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) { // In case we see two .cv_loc directives in a row, make sure the // first one gets a line entry. MCCVLineEntry::Make(this); this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt, FileName, Loc); } void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin, const MCSymbol *End) { getContext().getCVContext().emitLineTableForFunction(*this, FunctionId, Begin, End); this->MCStreamer::EmitCVLinetableDirective(FunctionId, Begin, End); } void MCObjectStreamer::EmitCVInlineLinetableDirective( unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) { getContext().getCVContext().emitInlineLineTableForFunction( *this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); this->MCStreamer::EmitCVInlineLinetableDirective( PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); } void MCObjectStreamer::EmitCVDefRangeDirective( ArrayRef> Ranges, StringRef FixedSizePortion) { getContext().getCVContext().emitDefRange(*this, Ranges, FixedSizePortion); this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion); } void MCObjectStreamer::EmitCVStringTableDirective() { getContext().getCVContext().emitStringTable(*this); } void MCObjectStreamer::EmitCVFileChecksumsDirective() { getContext().getCVContext().emitFileChecksums(*this); } void MCObjectStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) { getContext().getCVContext().emitFileChecksumOffset(*this, FileNo); } void MCObjectStreamer::EmitBytes(StringRef Data) { MCCVLineEntry::Make(this); MCDwarfLineEntry::Make(this, getCurrentSectionOnly()); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getContents().append(Data.begin(), Data.end()); } void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; insert(new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit)); // Update the maximum alignment on the current section if necessary. MCSection *CurSec = getCurrentSectionOnly(); if (ByteAlignment > CurSec->getAlignment()) CurSec->setAlignment(ByteAlignment); } void MCObjectStreamer::EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) { EmitValueToAlignment(ByteAlignment, 0, 1, MaxBytesToEmit); cast(getCurrentFragment())->setEmitNops(true); } void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value, SMLoc Loc) { insert(new MCOrgFragment(*Offset, Value, Loc)); } void MCObjectStreamer::EmitCodePaddingBasicBlockStart( const MCCodePaddingContext &Context) { getAssembler().getBackend().handleCodePaddingBasicBlockStart(this, Context); } void MCObjectStreamer::EmitCodePaddingBasicBlockEnd( const MCCodePaddingContext &Context) { getAssembler().getBackend().handleCodePaddingBasicBlockEnd(Context); } // Associate DTPRel32 fixup with data and resize data area void MCObjectStreamer::EmitDTPRel32Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), Value, FK_DTPRel_4)); DF->getContents().resize(DF->getContents().size() + 4, 0); } // Associate DTPRel64 fixup with data and resize data area void MCObjectStreamer::EmitDTPRel64Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), Value, FK_DTPRel_8)); DF->getContents().resize(DF->getContents().size() + 8, 0); } // Associate TPRel32 fixup with data and resize data area void MCObjectStreamer::EmitTPRel32Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), Value, FK_TPRel_4)); DF->getContents().resize(DF->getContents().size() + 4, 0); } // Associate TPRel64 fixup with data and resize data area void MCObjectStreamer::EmitTPRel64Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getFixups().push_back(MCFixup::create(DF->getContents().size(), Value, FK_TPRel_8)); DF->getContents().resize(DF->getContents().size() + 8, 0); } // Associate GPRel32 fixup with data and resize data area void MCObjectStreamer::EmitGPRel32Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getFixups().push_back( MCFixup::create(DF->getContents().size(), Value, FK_GPRel_4)); DF->getContents().resize(DF->getContents().size() + 4, 0); } // Associate GPRel64 fixup with data and resize data area void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getFixups().push_back( MCFixup::create(DF->getContents().size(), Value, FK_GPRel_4)); DF->getContents().resize(DF->getContents().size() + 8, 0); } bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) { int64_t OffsetValue; if (!Offset.evaluateAsAbsolute(OffsetValue)) llvm_unreachable("Offset is not absolute"); if (OffsetValue < 0) llvm_unreachable("Offset is negative"); MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); Optional MaybeKind = Assembler->getBackend().getFixupKind(Name); if (!MaybeKind.hasValue()) return true; MCFixupKind Kind = *MaybeKind; if (Expr == nullptr) Expr = MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext()); DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc)); return false; } void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue, SMLoc Loc) { MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); - int64_t IntNumBytes; - if (!NumBytes.evaluateAsAbsolute(IntNumBytes, getAssembler())) { - getContext().reportError(Loc, "expected absolute expression"); - return; - } - - if (IntNumBytes < 0) { - getContext().reportError(Loc, "invalid number of bytes"); - return; - } - assert(getCurrentSectionOnly() && "need a section"); - insert(new MCFillFragment(FillValue, IntNumBytes)); + insert(new MCFillFragment(FillValue, NumBytes, Loc)); } void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) { int64_t IntNumValues; if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssembler())) { getContext().reportError(Loc, "expected absolute expression"); return; } if (IntNumValues < 0) { getContext().getSourceManager()->PrintMessage( Loc, SourceMgr::DK_Warning, "'.fill' directive with negative repeat count has no effect"); return; } MCStreamer::emitFill(IntNumValues, Size, Expr); } void MCObjectStreamer::EmitFileDirective(StringRef Filename) { getAssembler().addFileName(Filename); } void MCObjectStreamer::FinishImpl() { // If we are generating dwarf for assembly source files dump out the sections. if (getContext().getGenDwarfForAssembly()) MCGenDwarfInfo::Emit(this); // Dump out the dwarf file & directory tables and line tables. MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams()); flushPendingLabels(nullptr); getAssembler().Finish(); } Index: head/contrib/llvm/lib/MC/WasmObjectWriter.cpp =================================================================== --- head/contrib/llvm/lib/MC/WasmObjectWriter.cpp (revision 328595) +++ head/contrib/llvm/lib/MC/WasmObjectWriter.cpp (revision 328596) @@ -1,1385 +1,1388 @@ //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements Wasm object file writer information. // //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/StringSaver.h" #include using namespace llvm; #define DEBUG_TYPE "mc" namespace { // For patching purposes, we need to remember where each section starts, both // for patching up the section size field, and for patching up references to // locations within the section. struct SectionBookkeeping { // Where the size of the section is written. uint64_t SizeOffset; // Where the contents of the section starts (after the header). uint64_t ContentsOffset; }; // The signature of a wasm function, in a struct capable of being used as a // DenseMap key. struct WasmFunctionType { // Support empty and tombstone instances, needed by DenseMap. enum { Plain, Empty, Tombstone } State; // The return types of the function. SmallVector Returns; // The parameter types of the function. SmallVector Params; WasmFunctionType() : State(Plain) {} bool operator==(const WasmFunctionType &Other) const { return State == Other.State && Returns == Other.Returns && Params == Other.Params; } }; // Traits for using WasmFunctionType in a DenseMap. struct WasmFunctionTypeDenseMapInfo { static WasmFunctionType getEmptyKey() { WasmFunctionType FuncTy; FuncTy.State = WasmFunctionType::Empty; return FuncTy; } static WasmFunctionType getTombstoneKey() { WasmFunctionType FuncTy; FuncTy.State = WasmFunctionType::Tombstone; return FuncTy; } static unsigned getHashValue(const WasmFunctionType &FuncTy) { uintptr_t Value = FuncTy.State; for (wasm::ValType Ret : FuncTy.Returns) Value += DenseMapInfo::getHashValue(int32_t(Ret)); for (wasm::ValType Param : FuncTy.Params) Value += DenseMapInfo::getHashValue(int32_t(Param)); return Value; } static bool isEqual(const WasmFunctionType &LHS, const WasmFunctionType &RHS) { return LHS == RHS; } }; // A wasm data segment. A wasm binary contains only a single data section // but that can contain many segments, each with their own virtual location // in memory. Each MCSection data created by llvm is modeled as its own // wasm data segment. struct WasmDataSegment { MCSectionWasm *Section; StringRef Name; uint32_t Offset; uint32_t Alignment; uint32_t Flags; SmallVector Data; }; // A wasm import to be written into the import section. struct WasmImport { StringRef ModuleName; StringRef FieldName; unsigned Kind; int32_t Type; bool IsMutable; }; // A wasm function to be written into the function section. struct WasmFunction { int32_t Type; const MCSymbolWasm *Sym; }; // A wasm export to be written into the export section. struct WasmExport { StringRef FieldName; unsigned Kind; uint32_t Index; }; // A wasm global to be written into the global section. struct WasmGlobal { wasm::ValType Type; bool IsMutable; bool HasImport; uint64_t InitialValue; uint32_t ImportIndex; }; // Information about a single relocation. struct WasmRelocationEntry { uint64_t Offset; // Where is the relocation. const MCSymbolWasm *Symbol; // The symbol to relocate with. int64_t Addend; // A value to add to the symbol. unsigned Type; // The type of the relocation. const MCSectionWasm *FixupSection;// The section the relocation is targeting. WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, int64_t Addend, unsigned Type, const MCSectionWasm *FixupSection) : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), FixupSection(FixupSection) {} bool hasAddend() const { switch (Type) { case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: return true; default: return false; } } void print(raw_ostream &Out) const { Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend << ", Type=" << Type << ", FixupSection=" << FixupSection->getSectionName(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { print(dbgs()); } #endif }; #if !defined(NDEBUG) raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { Rel.print(OS); return OS; } #endif class WasmObjectWriter : public MCObjectWriter { /// Helper struct for containing some precomputed information on symbols. struct WasmSymbolData { const MCSymbolWasm *Symbol; StringRef Name; // Support lexicographic sorting. bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; } }; /// The target specific Wasm writer instance. std::unique_ptr TargetObjectWriter; // Relocations for fixing up references in the code section. std::vector CodeRelocations; // Relocations for fixing up references in the data section. std::vector DataRelocations; // Index values to use for fixing up call_indirect type indices. // Maps function symbols to the index of the type of the function DenseMap TypeIndices; // Maps function symbols to the table element index space. Used // for TABLE_INDEX relocation types (i.e. address taken functions). DenseMap IndirectSymbolIndices; // Maps function/global symbols to the function/global index space. DenseMap SymbolIndices; DenseMap FunctionTypeIndices; SmallVector FunctionTypes; SmallVector Globals; unsigned NumGlobalImports = 0; // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const { return TargetObjectWriter->getRelocType(Target, Fixup); } void startSection(SectionBookkeeping &Section, unsigned SectionId, const char *Name = nullptr); void endSection(SectionBookkeeping &Section); public: WasmObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS) : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(std::move(MOTW)) {} private: ~WasmObjectWriter() override; void reset() override { CodeRelocations.clear(); DataRelocations.clear(); TypeIndices.clear(); SymbolIndices.clear(); IndirectSymbolIndices.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); Globals.clear(); MCObjectWriter::reset(); NumGlobalImports = 0; } void writeHeader(const MCAssembler &Asm); void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override; void executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) override; void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; void writeString(const StringRef Str) { encodeULEB128(Str.size(), getStream()); writeBytes(Str); } void writeValueType(wasm::ValType Ty) { encodeSLEB128(int32_t(Ty), getStream()); } void writeTypeSection(ArrayRef FunctionTypes); void writeImportSection(ArrayRef Imports, uint32_t DataSize, uint32_t NumElements); void writeFunctionSection(ArrayRef Functions); void writeGlobalSection(); void writeExportSection(ArrayRef Exports); void writeElemSection(ArrayRef TableElems); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef Functions); void writeDataSection(ArrayRef Segments); void writeNameSection(ArrayRef Functions, ArrayRef Imports, uint32_t NumFuncImports); void writeCodeRelocSection(); void writeDataRelocSection(); void writeLinkingMetaDataSection( ArrayRef Segments, uint32_t DataSize, const SmallVector, 4> &SymbolFlags, const SmallVector, 2> &InitFuncs); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, uint64_t ContentsOffset); void writeRelocations(ArrayRef Relocations); uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getFunctionType(const MCSymbolWasm& Symbol); uint32_t registerFunctionType(const MCSymbolWasm& Symbol); }; } // end anonymous namespace WasmObjectWriter::~WasmObjectWriter() {} // Write out a section header and a patchable section size field. void WasmObjectWriter::startSection(SectionBookkeeping &Section, unsigned SectionId, const char *Name) { assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && "Only custom sections can have names"); DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); encodeULEB128(SectionId, getStream()); Section.SizeOffset = getStream().tell(); // The section size. We don't know the size yet, so reserve enough space // for any 32-bit value; we'll patch it later. encodeULEB128(UINT32_MAX, getStream()); // The position where the section starts, for measuring its size. Section.ContentsOffset = getStream().tell(); // Custom sections in wasm also have a string identifier. if (SectionId == wasm::WASM_SEC_CUSTOM) { assert(Name); writeString(StringRef(Name)); } } // Now that the section is complete and we know how big it is, patch up the // section size field at the start of the section. void WasmObjectWriter::endSection(SectionBookkeeping &Section) { uint64_t Size = getStream().tell() - Section.ContentsOffset; if (uint32_t(Size) != Size) report_fatal_error("section size does not fit in a uint32_t"); DEBUG(dbgs() << "endSection size=" << Size << "\n"); // Write the final section size to the payload_len field, which follows // the section id byte. uint8_t Buffer[16]; unsigned SizeLen = encodeULEB128(Size, Buffer, 5); assert(SizeLen == 5); getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); } // Emit the Wasm header. void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic))); writeLE32(wasm::WasmVersion); } void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { } void WasmObjectWriter::recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { MCAsmBackend &Backend = Asm.getBackend(); bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; const auto &FixupSection = cast(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); // The .init_array isn't translated as data, so don't do relocations in it. if (FixupSection.getSectionName().startswith(".init_array")) return; if (const MCSymbolRefExpr *RefB = Target.getSymB()) { assert(RefB->getKind() == MCSymbolRefExpr::VK_None && "Should not have constructed this"); // Let A, B and C being the components of Target and R be the location of // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). // If it is pcrel, we want to compute (A - B + C - R). // In general, Wasm has no relocations for -B. It can only represent (A + C) // or (A + C - R). If B = R + K and the relocation is not pcrel, we can // replace B to implement it: (A - R - K + C) if (IsPCRel) { Ctx.reportError( Fixup.getLoc(), "No relocation available to represent this relative expression"); return; } const auto &SymB = cast(RefB->getSymbol()); if (SymB.isUndefined()) { Ctx.reportError(Fixup.getLoc(), Twine("symbol '") + SymB.getName() + "' can not be undefined in a subtraction expression"); return; } assert(!SymB.isAbsolute() && "Should have been folded"); const MCSection &SecB = SymB.getSection(); if (&SecB != &FixupSection) { Ctx.reportError(Fixup.getLoc(), "Cannot represent a difference across sections"); return; } uint64_t SymBOffset = Layout.getSymbolOffset(SymB); uint64_t K = SymBOffset - FixupOffset; IsPCRel = true; C -= K; } // We either rejected the fixup or folded B into C at this point. const MCSymbolRefExpr *RefA = Target.getSymA(); const auto *SymA = RefA ? cast(&RefA->getSymbol()) : nullptr; if (SymA && SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); const auto *Inner = cast(Expr); if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) llvm_unreachable("weakref used in reloc not yet implemented"); } // Put any constant offset in an addend. Offsets can be negative, and // LLVM expects wrapping, in contrast to wasm's immediates which can't // be negative and don't wrap. FixedValue = 0; if (SymA) SymA->setUsedInReloc(); assert(!IsPCRel); assert(SymA); unsigned Type = getRelocType(Target, Fixup); WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); if (FixupSection.isWasmData()) DataRelocations.push_back(Rec); else if (FixupSection.getKind().isText()) CodeRelocations.push_back(Rec); else if (!FixupSection.getKind().isMetadata()) // TODO(sbc): Add support for debug sections. llvm_unreachable("unexpected section type"); } // Write X as an (unsigned) LEB value at offset Offset in Stream, padded // to allow patching. static void WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { uint8_t Buffer[5]; unsigned SizeLen = encodeULEB128(X, Buffer, 5); assert(SizeLen == 5); Stream.pwrite((char *)Buffer, SizeLen, Offset); } // Write X as an signed LEB value at offset Offset in Stream, padded // to allow patching. static void WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { uint8_t Buffer[5]; unsigned SizeLen = encodeSLEB128(X, Buffer, 5); assert(SizeLen == 5); Stream.pwrite((char *)Buffer, SizeLen, Offset); } // Write X as a plain integer value at offset Offset in Stream. static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { uint8_t Buffer[4]; support::endian::write32le(Buffer, X); Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); } static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) { if (Symbol.isVariable()) { const MCExpr *Expr = Symbol.getVariableValue(); auto *Inner = cast(Expr); return cast(&Inner->getSymbol()); } return &Symbol; } // Compute a value to write into the code at the location covered // by RelEntry. This value isn't used by the static linker, since // we have addends; it just serves to make the code more readable // and to make standalone wasm modules directly usable. uint32_t WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); // For undefined symbols, use a hopefully invalid value. if (!Sym->isDefined(/*SetUsed=*/false)) return UINT32_MAX; uint32_t GlobalIndex = SymbolIndices[Sym]; const WasmGlobal& Global = Globals[GlobalIndex - NumGlobalImports]; uint64_t Address = Global.InitialValue + RelEntry.Addend; // Ignore overflow. LLVM allows address arithmetic to silently wrap. uint32_t Value = Address; return Value; } static void addData(SmallVectorImpl &DataBytes, MCSectionWasm &DataSection) { DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); size_t LastFragmentSize = 0; for (const MCFragment &Frag : DataSection) { if (Frag.hasInstructions()) report_fatal_error("only data supported in data sections"); if (auto *Align = dyn_cast(&Frag)) { if (Align->getValueSize() != 1) report_fatal_error("only byte values supported for alignment"); // If nops are requested, use zeros, as this is the data section. uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); uint64_t Size = std::min(alignTo(DataBytes.size(), Align->getAlignment()), DataBytes.size() + Align->getMaxBytesToEmit()); DataBytes.resize(Size, Value); } else if (auto *Fill = dyn_cast(&Frag)) { - DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue()); + int64_t Size; + if (!Fill->getSize().evaluateAsAbsolute(Size)) + llvm_unreachable("The fill should be an assembler constant"); + DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); } else { const auto &DataFrag = cast(Frag); const SmallVectorImpl &Contents = DataFrag.getContents(); DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); LastFragmentSize = Contents.size(); } } // Don't allow empty segments, or segments that end with zero-sized // fragment, otherwise the linker cannot map symbols to a unique // data segment. This can be triggered by zero-sized structs // See: test/MC/WebAssembly/bss.ll if (LastFragmentSize == 0) DataBytes.resize(DataBytes.size() + 1); DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); } uint32_t WasmObjectWriter::getRelocationIndexValue( const WasmRelocationEntry &RelEntry) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: if (!IndirectSymbolIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in table index space: " + RelEntry.Symbol->getName()); return IndirectSymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: if (!SymbolIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in function/global index space: " + RelEntry.Symbol->getName()); return SymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: if (!TypeIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in type index space: " + RelEntry.Symbol->getName()); return TypeIndices[RelEntry.Symbol]; default: llvm_unreachable("invalid relocation type"); } } // Apply the portions of the relocation records that we can handle ourselves // directly. void WasmObjectWriter::applyRelocations( ArrayRef Relocations, uint64_t ContentsOffset) { raw_pwrite_stream &Stream = getStream(); for (const WasmRelocationEntry &RelEntry : Relocations) { uint64_t Offset = ContentsOffset + RelEntry.FixupSection->getSectionOffset() + RelEntry.Offset; DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { uint32_t Index = getRelocationIndexValue(RelEntry); WritePatchableSLEB(Stream, Index, Offset); break; } case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { uint32_t Index = getRelocationIndexValue(RelEntry); WriteI32(Stream, Index, Offset); break; } case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { uint32_t Value = getProvisionalValue(RelEntry); WritePatchableSLEB(Stream, Value, Offset); break; } case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: { uint32_t Value = getProvisionalValue(RelEntry); WritePatchableLEB(Stream, Value, Offset); break; } case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: { uint32_t Value = getProvisionalValue(RelEntry); WriteI32(Stream, Value, Offset); break; } default: llvm_unreachable("invalid relocation type"); } } } // Write out the portions of the relocation records that the linker will // need to handle. void WasmObjectWriter::writeRelocations( ArrayRef Relocations) { raw_pwrite_stream &Stream = getStream(); for (const WasmRelocationEntry& RelEntry : Relocations) { uint64_t Offset = RelEntry.Offset + RelEntry.FixupSection->getSectionOffset(); uint32_t Index = getRelocationIndexValue(RelEntry); encodeULEB128(RelEntry.Type, Stream); encodeULEB128(Offset, Stream); encodeULEB128(Index, Stream); if (RelEntry.hasAddend()) encodeSLEB128(RelEntry.Addend, Stream); } } void WasmObjectWriter::writeTypeSection( ArrayRef FunctionTypes) { if (FunctionTypes.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_TYPE); encodeULEB128(FunctionTypes.size(), getStream()); for (const WasmFunctionType &FuncTy : FunctionTypes) { encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream()); encodeULEB128(FuncTy.Params.size(), getStream()); for (wasm::ValType Ty : FuncTy.Params) writeValueType(Ty); encodeULEB128(FuncTy.Returns.size(), getStream()); for (wasm::ValType Ty : FuncTy.Returns) writeValueType(Ty); } endSection(Section); } void WasmObjectWriter::writeImportSection(ArrayRef Imports, uint32_t DataSize, uint32_t NumElements) { if (Imports.empty()) return; uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_IMPORT); encodeULEB128(Imports.size(), getStream()); for (const WasmImport &Import : Imports) { writeString(Import.ModuleName); writeString(Import.FieldName); encodeULEB128(Import.Kind, getStream()); switch (Import.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: encodeULEB128(Import.Type, getStream()); break; case wasm::WASM_EXTERNAL_GLOBAL: encodeSLEB128(int32_t(Import.Type), getStream()); encodeULEB128(int32_t(Import.IsMutable), getStream()); break; case wasm::WASM_EXTERNAL_MEMORY: encodeULEB128(0, getStream()); // flags encodeULEB128(NumPages, getStream()); // initial break; case wasm::WASM_EXTERNAL_TABLE: encodeSLEB128(int32_t(Import.Type), getStream()); encodeULEB128(0, getStream()); // flags encodeULEB128(NumElements, getStream()); // initial break; default: llvm_unreachable("unsupported import kind"); } } endSection(Section); } void WasmObjectWriter::writeFunctionSection(ArrayRef Functions) { if (Functions.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_FUNCTION); encodeULEB128(Functions.size(), getStream()); for (const WasmFunction &Func : Functions) encodeULEB128(Func.Type, getStream()); endSection(Section); } void WasmObjectWriter::writeGlobalSection() { if (Globals.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_GLOBAL); encodeULEB128(Globals.size(), getStream()); for (const WasmGlobal &Global : Globals) { writeValueType(Global.Type); write8(Global.IsMutable); if (Global.HasImport) { assert(Global.InitialValue == 0); write8(wasm::WASM_OPCODE_GET_GLOBAL); encodeULEB128(Global.ImportIndex, getStream()); } else { assert(Global.ImportIndex == 0); write8(wasm::WASM_OPCODE_I32_CONST); encodeSLEB128(Global.InitialValue, getStream()); // offset } write8(wasm::WASM_OPCODE_END); } endSection(Section); } void WasmObjectWriter::writeExportSection(ArrayRef Exports) { if (Exports.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_EXPORT); encodeULEB128(Exports.size(), getStream()); for (const WasmExport &Export : Exports) { writeString(Export.FieldName); encodeSLEB128(Export.Kind, getStream()); encodeULEB128(Export.Index, getStream()); } endSection(Section); } void WasmObjectWriter::writeElemSection(ArrayRef TableElems) { if (TableElems.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_ELEM); encodeULEB128(1, getStream()); // number of "segments" encodeULEB128(0, getStream()); // the table index // init expr for starting offset write8(wasm::WASM_OPCODE_I32_CONST); encodeSLEB128(0, getStream()); write8(wasm::WASM_OPCODE_END); encodeULEB128(TableElems.size(), getStream()); for (uint32_t Elem : TableElems) encodeULEB128(Elem, getStream()); endSection(Section); } void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef Functions) { if (Functions.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CODE); encodeULEB128(Functions.size(), getStream()); for (const WasmFunction &Func : Functions) { auto &FuncSection = static_cast(Func.Sym->getSection()); int64_t Size = 0; if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); encodeULEB128(Size, getStream()); FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); Asm.writeSectionData(&FuncSection, Layout); } // Apply fixups. applyRelocations(CodeRelocations, Section.ContentsOffset); endSection(Section); } void WasmObjectWriter::writeDataSection(ArrayRef Segments) { if (Segments.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_DATA); encodeULEB128(Segments.size(), getStream()); // count for (const WasmDataSegment & Segment : Segments) { encodeULEB128(0, getStream()); // memory index write8(wasm::WASM_OPCODE_I32_CONST); encodeSLEB128(Segment.Offset, getStream()); // offset write8(wasm::WASM_OPCODE_END); encodeULEB128(Segment.Data.size(), getStream()); // size Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset); writeBytes(Segment.Data); // data } // Apply fixups. applyRelocations(DataRelocations, Section.ContentsOffset); endSection(Section); } void WasmObjectWriter::writeNameSection( ArrayRef Functions, ArrayRef Imports, unsigned NumFuncImports) { uint32_t TotalFunctions = NumFuncImports + Functions.size(); if (TotalFunctions == 0) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "name"); SectionBookkeeping SubSection; startSection(SubSection, wasm::WASM_NAMES_FUNCTION); encodeULEB128(TotalFunctions, getStream()); uint32_t Index = 0; for (const WasmImport &Import : Imports) { if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { encodeULEB128(Index, getStream()); writeString(Import.FieldName); ++Index; } } for (const WasmFunction &Func : Functions) { encodeULEB128(Index, getStream()); writeString(Func.Sym->getName()); ++Index; } endSection(SubSection); endSection(Section); } void WasmObjectWriter::writeCodeRelocSection() { // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. if (CodeRelocations.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); encodeULEB128(wasm::WASM_SEC_CODE, getStream()); encodeULEB128(CodeRelocations.size(), getStream()); writeRelocations(CodeRelocations); endSection(Section); } void WasmObjectWriter::writeDataRelocSection() { // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md // for descriptions of the reloc sections. if (DataRelocations.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); encodeULEB128(wasm::WASM_SEC_DATA, getStream()); encodeULEB128(DataRelocations.size(), getStream()); writeRelocations(DataRelocations); endSection(Section); } void WasmObjectWriter::writeLinkingMetaDataSection( ArrayRef Segments, uint32_t DataSize, const SmallVector, 4> &SymbolFlags, const SmallVector, 2> &InitFuncs) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); SectionBookkeeping SubSection; if (SymbolFlags.size() != 0) { startSection(SubSection, wasm::WASM_SYMBOL_INFO); encodeULEB128(SymbolFlags.size(), getStream()); for (auto Pair: SymbolFlags) { writeString(Pair.first); encodeULEB128(Pair.second, getStream()); } endSection(SubSection); } if (DataSize > 0) { startSection(SubSection, wasm::WASM_DATA_SIZE); encodeULEB128(DataSize, getStream()); endSection(SubSection); } if (Segments.size()) { startSection(SubSection, wasm::WASM_SEGMENT_INFO); encodeULEB128(Segments.size(), getStream()); for (const WasmDataSegment &Segment : Segments) { writeString(Segment.Name); encodeULEB128(Segment.Alignment, getStream()); encodeULEB128(Segment.Flags, getStream()); } endSection(SubSection); } if (!InitFuncs.empty()) { startSection(SubSection, wasm::WASM_INIT_FUNCS); encodeULEB128(InitFuncs.size(), getStream()); for (auto &StartFunc : InitFuncs) { encodeULEB128(StartFunc.first, getStream()); // priority encodeULEB128(StartFunc.second, getStream()); // function index } endSection(SubSection); } endSection(Section); } uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); return TypeIndices[&Symbol]; } uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); WasmFunctionType F; const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol); F.Returns = ResolvedSym->getReturns(); F.Params = ResolvedSym->getParams(); auto Pair = FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); if (Pair.second) FunctionTypes.push_back(F); TypeIndices[&Symbol] = Pair.first->second; DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n"); DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); return Pair.first->second; } void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); MCContext &Ctx = Asm.getContext(); wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; // Collect information from the available symbols. SmallVector Functions; SmallVector TableElems; SmallVector Imports; SmallVector Exports; SmallVector, 4> SymbolFlags; SmallVector, 2> InitFuncs; unsigned NumFuncImports = 0; SmallVector DataSegments; uint32_t DataSize = 0; // In the special .global_variables section, we've encoded global // variables used by the function. Translate them into the Globals // list. MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", SectionKind::getMetadata()); if (!GlobalVars->getFragmentList().empty()) { if (GlobalVars->getFragmentList().size() != 1) report_fatal_error("only one .global_variables fragment supported"); const MCFragment &Frag = *GlobalVars->begin(); if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) report_fatal_error("only data supported in .global_variables"); const auto &DataFrag = cast(Frag); if (!DataFrag.getFixups().empty()) report_fatal_error("fixups not supported in .global_variables"); const SmallVectorImpl &Contents = DataFrag.getContents(); for (const uint8_t *p = (const uint8_t *)Contents.data(), *end = (const uint8_t *)Contents.data() + Contents.size(); p != end; ) { WasmGlobal G; if (end - p < 3) report_fatal_error("truncated global variable encoding"); G.Type = wasm::ValType(int8_t(*p++)); G.IsMutable = bool(*p++); G.HasImport = bool(*p++); if (G.HasImport) { G.InitialValue = 0; WasmImport Import; Import.ModuleName = (const char *)p; const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p); if (!nul) report_fatal_error("global module name must be nul-terminated"); p = nul + 1; nul = (const uint8_t *)memchr(p, '\0', end - p); if (!nul) report_fatal_error("global base name must be nul-terminated"); Import.FieldName = (const char *)p; p = nul + 1; Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; Import.Type = int32_t(G.Type); G.ImportIndex = NumGlobalImports; ++NumGlobalImports; Imports.push_back(Import); } else { unsigned n; G.InitialValue = decodeSLEB128(p, &n); G.ImportIndex = 0; if ((ptrdiff_t)n > end - p) report_fatal_error("global initial value must be valid SLEB128"); p += n; } Globals.push_back(G); } } // For now, always emit the memory import, since loads and stores are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no loads or stores. MCSymbolWasm *MemorySym = cast(Ctx.getOrCreateSymbol("__linear_memory")); WasmImport MemImport; MemImport.ModuleName = MemorySym->getModuleName(); MemImport.FieldName = MemorySym->getName(); MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; Imports.push_back(MemImport); // For now, always emit the table section, since indirect calls are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no indirect calls. MCSymbolWasm *TableSym = cast(Ctx.getOrCreateSymbol("__indirect_function_table")); WasmImport TableImport; TableImport.ModuleName = TableSym->getModuleName(); TableImport.FieldName = TableSym->getName(); TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; TableImport.Type = wasm::WASM_TYPE_ANYFUNC; Imports.push_back(TableImport); // Populate FunctionTypeIndices and Imports. for (const MCSymbol &S : Asm.symbols()) { const auto &WS = static_cast(S); // Register types for all functions, including those with private linkage // (making them // because wasm always needs a type signature. if (WS.isFunction()) registerFunctionType(WS); if (WS.isTemporary()) continue; // If the symbol is not defined in this translation unit, import it. if (!WS.isDefined(/*SetUsed=*/false) || WS.isVariable()) { WasmImport Import; Import.ModuleName = WS.getModuleName(); Import.FieldName = WS.getName(); if (WS.isFunction()) { Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; Import.Type = getFunctionType(WS); SymbolIndices[&WS] = NumFuncImports; ++NumFuncImports; } else { Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; Import.Type = int32_t(PtrType); Import.IsMutable = false; SymbolIndices[&WS] = NumGlobalImports; // If this global is the stack pointer, make it mutable. if (WS.getName() == "__stack_pointer") Import.IsMutable = true; ++NumGlobalImports; } Imports.push_back(Import); } } for (MCSection &Sec : Asm) { auto &Section = static_cast(Sec); if (!Section.isWasmData()) continue; // .init_array sections are handled specially elsewhere. if (cast(Sec).getSectionName().startswith(".init_array")) continue; DataSize = alignTo(DataSize, Section.getAlignment()); DataSegments.emplace_back(); WasmDataSegment &Segment = DataSegments.back(); Segment.Name = Section.getSectionName(); Segment.Offset = DataSize; Segment.Section = &Section; addData(Segment.Data, Section); Segment.Alignment = Section.getAlignment(); Segment.Flags = 0; DataSize += Segment.Data.size(); Section.setMemoryOffset(Segment.Offset); } // Handle regular defined and undefined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, // or used in relocations. if (S.isTemporary() && S.getName().empty()) continue; const auto &WS = static_cast(S); DEBUG(dbgs() << "MCSymbol: '" << S << "'" << " isDefined=" << S.isDefined() << " isExternal=" << S.isExternal() << " isTemporary=" << S.isTemporary() << " isFunction=" << WS.isFunction() << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden() << " isVariable=" << WS.isVariable() << "\n"); if (WS.isWeak() || WS.isHidden()) { uint32_t Flags = (WS.isWeak() ? wasm::WASM_SYMBOL_BINDING_WEAK : 0) | (WS.isHidden() ? wasm::WASM_SYMBOL_VISIBILITY_HIDDEN : 0); SymbolFlags.emplace_back(WS.getName(), Flags); } if (WS.isVariable()) continue; unsigned Index; if (WS.isFunction()) { if (WS.isDefined(/*SetUsed=*/false)) { if (WS.getOffset() != 0) report_fatal_error( "function sections must contain one function each"); if (WS.getSize() == 0) report_fatal_error( "function symbols must have a size set with .size"); // A definition. Take the next available index. Index = NumFuncImports + Functions.size(); // Prepare the function. WasmFunction Func; Func.Type = getFunctionType(WS); Func.Sym = &WS; SymbolIndices[&WS] = Index; Functions.push_back(Func); } else { // An import; the index was assigned above. Index = SymbolIndices.find(&WS)->second; } DEBUG(dbgs() << " -> function index: " << Index << "\n"); } else { if (WS.isTemporary() && !WS.getSize()) continue; if (!WS.isDefined(/*SetUsed=*/false)) continue; if (!WS.getSize()) report_fatal_error("data symbols must have a size set with .size: " + WS.getName()); int64_t Size = 0; if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); // For each global, prepare a corresponding wasm global holding its // address. For externals these will also be named exports. Index = NumGlobalImports + Globals.size(); auto &DataSection = static_cast(WS.getSection()); WasmGlobal Global; Global.Type = PtrType; Global.IsMutable = false; Global.HasImport = false; Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); Global.ImportIndex = 0; SymbolIndices[&WS] = Index; DEBUG(dbgs() << " -> global index: " << Index << "\n"); Globals.push_back(Global); } // If the symbol is visible outside this translation unit, export it. if (WS.isDefined(/*SetUsed=*/false)) { WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; if (WS.isFunction()) Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; else Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); Exports.push_back(Export); if (!WS.isExternal()) SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); } } // Handle weak aliases. We need to process these in a separate pass because // we need to have processed the target of the alias before the alias itself // and the symbols are not necessarily ordered in this way. for (const MCSymbol &S : Asm.symbols()) { if (!S.isVariable()) continue; assert(S.isDefined(/*SetUsed=*/false)); // Find the target symbol of this weak alias and export that index const auto &WS = static_cast(S); const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); assert(SymbolIndices.count(ResolvedSym) > 0); uint32_t Index = SymbolIndices.find(ResolvedSym)->second; DEBUG(dbgs() << " -> index:" << Index << "\n"); WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; if (WS.isFunction()) Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; else Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); Exports.push_back(Export); if (!WS.isExternal()) SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); } { auto HandleReloc = [&](const WasmRelocationEntry &Rel) { // Functions referenced by a relocation need to prepared to be called // indirectly. const MCSymbolWasm& WS = *Rel.Symbol; if (WS.isFunction() && IndirectSymbolIndices.count(&WS) == 0) { switch (Rel.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { uint32_t Index = SymbolIndices.find(&WS)->second; IndirectSymbolIndices[&WS] = TableElems.size(); DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n"); TableElems.push_back(Index); registerFunctionType(WS); break; } default: break; } } }; for (const WasmRelocationEntry &RelEntry : CodeRelocations) HandleReloc(RelEntry); for (const WasmRelocationEntry &RelEntry : DataRelocations) HandleReloc(RelEntry); } // Translate .init_array section contents into start functions. for (const MCSection &S : Asm) { const auto &WS = static_cast(S); if (WS.getSectionName().startswith(".fini_array")) report_fatal_error(".fini_array sections are unsupported"); if (!WS.getSectionName().startswith(".init_array")) continue; if (WS.getFragmentList().empty()) continue; if (WS.getFragmentList().size() != 2) report_fatal_error("only one .init_array section fragment supported"); const MCFragment &AlignFrag = *WS.begin(); if (AlignFrag.getKind() != MCFragment::FT_Align) report_fatal_error(".init_array section should be aligned"); if (cast(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4)) report_fatal_error(".init_array section should be aligned for pointers"); const MCFragment &Frag = *std::next(WS.begin()); if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) report_fatal_error("only data supported in .init_array section"); uint16_t Priority = UINT16_MAX; if (WS.getSectionName().size() != 11) { if (WS.getSectionName()[11] != '.') report_fatal_error(".init_array section priority should start with '.'"); if (WS.getSectionName().substr(12).getAsInteger(10, Priority)) report_fatal_error("invalid .init_array section priority"); } const auto &DataFrag = cast(Frag); const SmallVectorImpl &Contents = DataFrag.getContents(); for (const uint8_t *p = (const uint8_t *)Contents.data(), *end = (const uint8_t *)Contents.data() + Contents.size(); p != end; ++p) { if (*p != 0) report_fatal_error("non-symbolic data in .init_array section"); } for (const MCFixup &Fixup : DataFrag.getFixups()) { assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false)); const MCExpr *Expr = Fixup.getValue(); auto *Sym = dyn_cast(Expr); if (!Sym) report_fatal_error("fixups in .init_array should be symbol references"); if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION) report_fatal_error("symbols in .init_array should be for functions"); auto I = SymbolIndices.find(cast(&Sym->getSymbol())); if (I == SymbolIndices.end()) report_fatal_error("symbols in .init_array should be defined"); uint32_t Index = I->second; InitFuncs.push_back(std::make_pair(Priority, Index)); } } // Write out the Wasm header. writeHeader(Asm); writeTypeSection(FunctionTypes); writeImportSection(Imports, DataSize, TableElems.size()); writeFunctionSection(Functions); // Skip the "table" section; we import the table instead. // Skip the "memory" section; we import the memory instead. writeGlobalSection(); writeExportSection(Exports); writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); writeDataSection(DataSegments); writeNameSection(Functions, Imports, NumFuncImports); writeCodeRelocSection(); writeDataRelocSection(); writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, InitFuncs); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. } std::unique_ptr llvm::createWasmObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS) { // FIXME: Can't use make_unique(...) as WasmObjectWriter's // destructor is private. Is that necessary? return std::unique_ptr( new WasmObjectWriter(std::move(MOTW), OS)); }